* The cache buffer are pointed to by a cache_head structure.
*/
-static struct cache_struct cache_head, cache[MAX_CACHE_ENTRIES];
-static int cache_block_size;
-static int cache_entries;
-
/**
* cache_init:
*
* regs->eax.l stores the block size(in bits not bytes)
*
*/
-void cache_init(com32sys_t * regs)
+void cache_init(struct device *dev, int block_size_shift)
{
struct cache_struct *prev, *cur;
- char *data = core_cache_buf;
- int block_size_shift = regs->eax.l;
+ char *data = dev->cache_data;
+ static __lowmem struct cache_struct cache_head, cache[MAX_CACHE_ENTRIES];
int i;
+
+ dev->cache_head = &cache_head;
+ dev->cache_block_size = 1 << block_size_shift;
+ dev->cache_entries = dev->cache_size >> block_size_shift;
+ if (dev->cache_entries > MAX_CACHE_ENTRIES)
+ dev->cache_entries = MAX_CACHE_ENTRIES;
- cache_block_size = 1 << block_size_shift;
- cache_entries = sizeof(core_cache_buf) >> block_size_shift;
- if (cache_entries > MAX_CACHE_ENTRIES)
- cache_entries = MAX_CACHE_ENTRIES;
-
- cache_head.prev = &cache[cache_entries-1];
+ cache_head.prev = &cache[dev->cache_entries-1];
cache_head.prev->next = &cache_head;
prev = &cache_head;
- for (i = 0; i < cache_entries; i++) {
+ for (i = 0; i < dev->cache_entries; i++) {
cur = &cache[i];
cur->block = 0;
cur->prev = prev;
prev->next = cur;
cur->data = data;
- data += cache_block_size;
+ data += dev->cache_block_size;
prev = cur++;
}
}
* @return: the data stores at gs:si
*
*/
-struct cache_struct* get_cache_block(block_t block)
+struct cache_struct* get_cache_block(struct device *dev, block_t block)
{
/* let's find it from the end, 'cause the endest is the freshest */
- struct cache_struct *cs = cache_head.prev;
+ struct cache_struct *cs = dev->cache_head->prev;
struct cache_struct *head, *last;
int i;
if (cs->block == block)
goto out;
- for (i = 0; i < cache_entries; i ++) {
+ for (i = 0; i < dev->cache_entries; i ++) {
if (cs->block == block)
break;
else
}
/* missed, so we need to load it */
- if (i == cache_entries) {
+ if (i == dev->cache_entries) {
/* store it at the head of real cache */
- cs = cache_head.next;
+ cs = dev->cache_head->next;
cs->block = block;
- getoneblk(cs->data, block, cache_block_size);
+ getoneblk(cs->data, block, dev->cache_block_size);
missed ++;
}
cs->next->prev = cs->prev;
/* add to just before head node */
- last = cache_head.prev;
- head = &cache_head;
+ last = dev->cache_head->prev;
+ head = dev->cache_head;
last->next = cs;
cs->prev = last;
cs->next = head;
out:
-#if 0 /* testing how efficiency the cache is */
total_read ++;
+#if 0 /* testing how efficiency the cache is */
if (total_read % 5 == 0)
printf("total_read %d\tmissed %d\n", total_read, missed);
#endif
/* in fact, that would never be happened */
if ((char *)(cs->data) > (char*)0x100000)
- printf("the buffer addres higher than 1M limit\n\r");
+ printf("the buffer addres higher than 1M limit\n");
return cs;
}
+
+
+/**
+ * Just print the sector, and according the LRU algorithm,
+ * Left most value is the most least secotr, and Right most
+ * value is the most Recent sector. I see it's a Left Right Used
+ * (LRU) algorithm; Just kidding:)
+ */
+void print_cache(struct device *dev)
+{
+ int i = 0;
+ struct cache_struct *cs = dev->cache_head;
+ for (; i < dev->cache_entries; i++) {
+ cs = cs->next;
+ printf("%d(%p) ", cs->block, cs->data);
+ }
+
+ printf("\n");
+}
#include "core.h"
#include "disk.h"
#include "ext2_fs.h"
+#include "fs.h"
#define FILENAME_MAX_LG2 8
#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
* any whitespace.
*
*/
-void mangle_name(com32sys_t *regs)
+void ext2_mangle_name(char *dst, char *src)
{
- char *src = (char *)MK_PTR(regs->ds, regs->esi.w[0]);
- char *dst = (char *)MK_PTR(regs->es, regs->edi.w[0]);
char *p = dst;
int i = FILENAME_MAX -1;
* @return: the pointer of the group's descriptor
*
*/
-struct ext2_group_desc *get_group_desc(uint32_t group_num)
+struct ext2_group_desc *get_group_desc(struct fs_info *fs, uint32_t group_num)
{
block_t block_num;
uint32_t offset;
offset = group_num % DescPerBlock;
block_num += sb->s_first_data_block + 1;
- cs = get_cache_block(block_num);
+ cs = get_cache_block(fs->fs_dev, block_num);
desc = (struct ext2_group_desc *)cs->data + offset;
* @param: offset, same as block
*
*/
-void read_inode(uint32_t inode_offset,
+void read_inode(struct fs_info *fs, uint32_t inode_offset,
struct ext2_inode *dst, struct ext2_group_desc *desc,
block_t *block, uint32_t *offset)
{
*block = inode_offset / InodePerBlock + desc->bg_inode_table;
*offset = inode_offset % InodePerBlock;
- cs = get_cache_block(*block);
+ cs = get_cache_block(fs->fs_dev, *block);
/* well, in EXT4, the inode structure usually be 256 */
inode = (struct ext2_inode *)(cs->data + (*offset * (sb->s_inode_size)));
* the first 128 bytes of the inode, stores in ThisInode
*
*/
-struct open_file_t * open_inode(uint32_t inr, uint32_t *file_len)
+struct open_file_t * open_inode(struct fs_info *fs, uint32_t inr, uint32_t *file_len)
{
struct open_file_t *file;
struct ext2_group_desc *desc;
inode_group = inr / sb->s_inodes_per_group;
/* get the group desc */
- desc = get_group_desc(inode_group);
+ desc = get_group_desc(fs, inode_group);
inode_offset = inr % sb->s_inodes_per_group;
- read_inode(inode_offset, this_inode, desc, &block_num, &block_off);
+ read_inode(fs, inode_offset, this_inode, desc, &block_num, &block_off);
/* Finally, we need to convet it to sector for now */
file->file_in_sec = (block_num<<ClustShift) + (block_off>>SECTOR_SHIFT);
struct ext4_extent_header *
-ext4_find_leaf (struct ext4_extent_header *eh, block_t block)
+ext4_find_leaf (struct fs_info *fs, struct ext4_extent_header *eh, block_t block)
{
struct ext4_extent_idx *index;
struct cache_struct *cs;
blk = (blk << 32) + index[i].ei_leaf_lo;
/* read the blk to memeory */
- cs = get_cache_block(blk);
+ cs = get_cache_block(fs->fs_dev, blk);
eh = (struct ext4_extent_header *)(cs->data);
}
}
/* handle the ext4 extents to get the phsical block number */
-uint64_t linsector_extent(block_t block, struct ext2_inode *inode)
+uint64_t linsector_extent(struct fs_info *fs, block_t block, struct ext2_inode *inode)
{
struct ext4_extent_header *leaf;
struct ext4_extent *ext;
int i;
uint64_t start;
- leaf = ext4_find_leaf((struct ext4_extent_header*)inode->i_block,block);
+ leaf = ext4_find_leaf(fs, (struct ext4_extent_header*)inode->i_block, block);
if (! leaf) {
printf("ERROR, extent leaf not found\n");
return 0;
*
* @return: the physic block number
*/
-block_t linsector_direct(block_t block, struct ext2_inode *inode)
+block_t linsector_direct(struct fs_info *fs, block_t block, struct ext2_inode *inode)
{
struct cache_struct *cs;
block -= EXT2_NDIR_BLOCKS;
if (block < PtrsPerBlock1) {
block_t ind_block = inode->i_block[EXT2_IND_BLOCK];
- cs = get_cache_block(ind_block);
+ cs = get_cache_block(fs->fs_dev, ind_block);
return ((block_t *)cs->data)[block];
}
block -= PtrsPerBlock1;
if (block < PtrsPerBlock2) {
block_t dou_block = inode->i_block[EXT2_DIND_BLOCK];
- cs = get_cache_block(dou_block);
+ cs = get_cache_block(fs->fs_dev, dou_block);
dou_block = ((block_t *)cs->data)[block / PtrsPerBlock1];
- cs = get_cache_block(dou_block);
+ cs = get_cache_block(fs->fs_dev, dou_block);
return ((block_t*)cs->data)[block % PtrsPerBlock1];
}
block -= PtrsPerBlock2;
if (block < PtrsPerBlock3) {
block_t tri_block = inode->i_block[EXT2_TIND_BLOCK];
- cs = get_cache_block(tri_block);
+ cs = get_cache_block(fs->fs_dev, tri_block);
tri_block = ((block_t *)cs->data)[block / PtrsPerBlock2];
- cs = get_cache_block(tri_block);
+ cs = get_cache_block(fs->fs_dev, tri_block);
tri_block = ((block_t *)cs->data)[block % PtrsPerBlock2];
- cs = get_cache_block(tri_block);
+ cs = get_cache_block(fs->fs_dev, tri_block);
return ((uint32_t*)cs->data)[block % PtrsPerBlock1];
}
*
* @return: physic sector number
*/
-sector_t linsector(sector_t lin_sector)
+sector_t linsector(struct fs_info *fs, sector_t lin_sector)
{
block_t block = lin_sector >> ClustShift;
struct ext2_inode *inode;
inode = this_inode;
if (inode->i_flags & EXT4_EXTENTS_FLAG)
- block = linsector_extent(block, inode);
+ block = linsector_extent(fs, block, inode);
else
- block = (uint32_t)linsector_direct(block, inode);
+ block = (uint32_t)linsector_direct(fs, block, inode);
if (!block) {
printf("ERROR: something error happend at linsector..\n");
* @return: ECX(of regs), number of bytes read
*
*/
-void getfssec(com32sys_t *regs)
+uint32_t ext2_getfssec(struct fs_info *fs, char *buf,
+ void *open_file, int sectors, int *have_more)
{
int sector_left, next_sector, sector_idx;
int frag_start, con_sec_cnt;
- int sectors = regs->ecx.w[0];
int bytes_read = sectors << SECTOR_SHIFT;
- char *buf;
- struct open_file_t *file;
-
- buf = (char *)MK_PTR(regs->es, regs->ebx.w[0]);
- file = (struct open_file_t *)MK_PTR(regs->ds, regs->esi.w[0]);
+ struct open_file_t *file = (struct open_file_t *)open_file;
sector_left = (file->file_bytesleft + SECTOR_SIZE - 1) >> SECTOR_SHIFT;
if (sectors > sector_left)
* get the frament
*/
sector_idx = file->file_sector;
- next_sector = frag_start = linsector(sector_idx);
+ next_sector = frag_start = linsector(fs, sector_idx);
con_sec_cnt = 0;
/* get the consective sectors count */
sector_idx ++;
next_sector ++;
- }while(next_sector == linsector(sectors));
+ }while(next_sector == linsector(fs, sectors));
#if 0
printf("You are reading stores at sector --0x%x--0x%x\n",
file->file_sector += con_sec_cnt; /* next sector index */
}while(sectors);
- if (bytes_read >= file->file_bytesleft) {
+ if (bytes_read >= file->file_bytesleft) {
bytes_read = file->file_bytesleft;
- regs->esi.w[0] = 0; /* do close the file for asm function*/
- }
+ *have_more = 0;
+ } else
+ *have_more = 1;
file->file_bytesleft -= bytes_read;
-
- regs->ecx.l = bytes_read;
-}
-
-
-/* This is the gefssec function that should be called from C function */
-void getfssec_ext(char *buf, struct open_file_t *file,
- int sectors, int *have_more)
-{
- com32sys_t regs;
-
- memset(®s, 0, sizeof regs);
-
- /*
- * for now, even though the buf and file structure are stored
- * at low address, BUT find:
- *
- * we can't use SEG stuff here, say the address of buf
- * is 0x800(found in debug), the address would be broken like
- * this: es = 0x80, bx = 0, while that's not the getfssec
- * function need.
- *
- * so we just do like:
- * regs.ebx.w[0] = buf;
- */
- regs.ebx.w[0] = OFFS_WRT(buf, 0);
- regs.esi.w[0] = OFFS_WRT(file, 0);
- regs.ecx.w[0] = sectors;
- getfssec(®s);
-
- *have_more = 1;
-
- /* the file is closed ? */
- if(!file->file_bytesleft)
- *have_more = 0;
+ return bytes_read;
}
-
+
+
/**
* find_dir_entry:
* find a dir entry, if find return it or return NULL
*
*/
-struct ext2_dir_entry* find_dir_entry(struct open_file_t *file, char *filename)
+struct ext2_dir_entry* find_dir_entry(struct fs_info *fs, struct open_file_t *file,char *filename)
{
int have_more;
char *EndBlock = trackbuf + (SecPerClust << SECTOR_SHIFT);;
struct ext2_dir_entry *de;
/* read a clust at a time */
- getfssec_ext(trackbuf, file, SecPerClust, &have_more);
+ ext2_getfssec(fs, trackbuf, file, SecPerClust, &have_more);
de = (struct ext2_dir_entry *)trackbuf;
while (1) {
if ((char *)de >= (char *)EndBlock) {
if (!have_more)
return NULL;
- getfssec_ext(trackbuf, file,SecPerClust,&have_more);
+ ext2_getfssec(fs, trackbuf, file,SecPerClust,&have_more);
de = (struct ext2_dir_entry *)trackbuf;
}
}
-char* do_symlink(struct open_file_t *file, uint32_t file_len, char *filename)
+char* do_symlink(struct fs_info *fs, struct open_file_t *file,
+ uint32_t file_len, char *filename)
{
int flag, have_more;
} else {
/* slow symlink */
- getfssec_ext(SymlinkTmpBuf,file,SYMLINK_SECTORS,&have_more);
+ ext2_getfssec(fs, SymlinkTmpBuf,file,SYMLINK_SECTORS,&have_more);
lnk_end = SymlinkTmpBuf + file_len;
}
* @out : file lenght in bytes, stores in eax
*
*/
-void searchdir(com32sys_t * regs)
+void ext2_searchdir(char *filename, struct file *file)
{
extern int CurrentDir;
- struct open_file_t *file;
+ struct open_file_t *open_file;
struct ext2_dir_entry *de;
uint8_t file_mode;
uint8_t SymlinkCtr = MAX_SYMLINKS;
uint32_t inr = CurrentDir;
uint32_t ThisDir = CurrentDir;
uint32_t file_len;
- char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);
-
+
begin_path:
while (*filename == '/') { /* Absolute filename */
inr = EXT2_ROOT_INO;
filename ++;
}
open:
- if ((file = open_inode(inr, &file_len)) == NULL)
+ if ((open_file = open_inode(file->fs, inr, &file_len)) == NULL)
goto err_noclose;
- file_mode = file->file_mode >> S_IFSHIFT;
+ file_mode = open_file->file_mode >> S_IFSHIFT;
/* It's a file */
if (file_mode == T_IFREG) {
while (*filename == '/')
filename ++;
- de = find_dir_entry(file, filename);
+ de = find_dir_entry(file->fs, open_file, filename);
if (!de)
goto err;
inr = de->d_inode;
filename += de->d_name_len;
- close_file(file);
+ close_file(open_file);
goto open;
}
if (--SymlinkCtr==0 || file_len>=SYMLINK_SECTORS*SECTOR_SIZE)
goto err; /* too many links or symlink too long */
- filename = do_symlink(file, file_len, filename);
+ filename = do_symlink(file->fs, open_file, file_len, filename);
if (!filename)
goto err_noclose;/* buffer overflow */
/* Otherwise, something bad ... */
err:
- close_file(file);
+ close_file(open_file);
err_noclose:
file_len = 0;
- file = NULL;
- regs->eflags.l |= EFLAGS_ZF;
+ open_file = NULL;
done:
- regs->eax.l = file_len;
- regs->esi.w[0] = OFFS_WRT(file, 0);
+ file->file_len = file_len;
+ file->open_file = (void*)open_file;
+
+#if 1
+ if (open_file) {
+ printf("file bytesleft: %d\n", open_file->file_bytesleft);
+ printf("file sector : %d\n", open_file->file_sector);
+ printf("file in sector: %d\n", open_file->file_in_sec);
+ printf("file offsector: %d\n", open_file->file_in_off);
+ }
+#endif
+
+}
+
+void ext2_load_config(com32sys_t *regs)
+{
+ char *config_name = "extlinux.conf";
+ com32sys_t out_regs;
+
+ strcpy(ConfigName, config_name);
+ *(uint32_t *)CurrentDirName = 0x00002f2e;
+
+ regs->edi.w[0] = ConfigName;
+ memset(&out_regs, 0, sizeof out_regs);
+ call16(core_open, regs, &out_regs);
+
+ regs->eax.w[0] = out_regs.eax.w[0];
+
+#if 0
+ printf("the zero flag is %s\n", regs->eax.w[0] ? \
+ "CLEAR, means we found the config file" :
+ "SET, menas we didn't find the config file");
+#endif
}
/**
- * init. the fs meta data, return the block size in eax
+ * init. the fs meta data, return the block size bits.
*/
-void init_fs(com32sys_t *regs)
+int ext2_fs_init(void)
{
extern char SuperBlock[1024];
PtrsPerBlock2 = 1 << ((ClustByteShift - 2) * 2);
PtrsPerBlock3 = 1 << ((ClustByteShift - 2) * 3);
- regs->eax.l = ClustByteShift;
+ return ClustByteShift;
}
+
+const struct fs_ops ext2_fs_ops = {
+ .fs_name = "ext2",
+ .fs_init = ext2_fs_init,
+ .searchdir = ext2_searchdir,
+ .getfssec = ext2_getfssec,
+ .mangle_name = ext2_mangle_name,
+ .unmangle_name = NULL,
+ .load_config = ext2_load_config
+};
#include "cache.h"
-/* The this pointer */
+/* The this fs pointer */
struct fs_info *this_fs;
struct fs_info fs;
struct device dev;
file.open_file = MK_PTR(regs->ds, regs->esi.w[0]);
file.fs = this_fs;
- bytes_read = this_fs->fs_ops->getfssec(buf, file.open_file, sectors, &have_more);
+ bytes_read = this_fs->fs_ops->getfssec(file.fs, buf, file.open_file, sectors, &have_more);
/* if we reach the EOF, set the si to be NULL */
if (!have_more)
char *filename = (char *)MK_PTR(regs->ds, regs->edi.w[0]);
struct file file;
+ printf("filename: %s\n", filename);
+
memset(&file, 0, sizeof file);
file.fs = this_fs;
this_fs->fs_ops->searchdir(filename, &file);
regs->esi.w[0] = OFFS_WRT(file.open_file, 0);
regs->eax.l = file.file_len;
+ if (!file.file_len)
+ regs->eflags.l |= EFLAGS_ZF;
+}
+
+/*
+ * well, I find that in the diskstart.inc, there's no room fow us to
+ * get the edd check result, so we implement a new one here.
+ */
+uint8_t detect_edd(uint8_t device_num)
+{
+ com32sys_t iregs, oregs;
+
+ /* Sending int 13h func 41h to query EBIOS information */
+ memset(&iregs, 0, sizeof iregs);
+ memset(&oregs, 0, sizeof oregs);
+
+ /* Get EBIOS support */
+ iregs.eax.w[0] = 0x4100;
+ iregs.ebx.w[0] = 0x55aa;
+ iregs.edx.b[0] = device_num;
+ iregs.eflags.b[0] = 0x3; /* CF set */
+
+ __intcall(0x13, &iregs, &oregs);
+
+ /* Detecting EDD support */
+ if (!(oregs.eflags.l & EFLAGS_CF) &&
+ oregs.ebx.w[0] == 0xaa55 && (oregs.ecx.b[0] & 1))
+ return 1;
+ else
+ return 0;
}
/*
* initialize the device structure
*/
-void device_init(struct device *dev, uint8_t drive_num,
- uint8_t type, sector_t offset)
+void device_init(struct device *dev, uint8_t device_num, sector_t offset)
{
- dev->device_number = drive_num;
+ dev->device_number = device_num;
dev->part_start = offset;
- dev->type = type;
-
+
+ dev->type = detect_edd(device_num);
+
/*
* check if we use cache or not, for now I just know ISO fs
* does not use the cache, and I hope the USE_CACHE can detect
* it correctly.
*
- */
+ */
if ( USE_CACHE(dev->device_number) ) {
- static __lowmem char cache_buf[65536];
- dev->cache_data = cache_buf;
+ /* I can't use __lowmem here, 'cause it will cause the error:
+ "auxseg/lowmem region collides with xfer_buf_seg" */
+ //static __lowmem char cache_buf[65536];
+ dev->cache_data = core_cache_buf;
+ dev->cache_size = sizeof core_cache_buf;
} else
dev->cache_data = NULL;
}
+/* debug function */
+void dump_dev(struct device *dev)
+{
+ printf("device type:%s\n", dev->type ? "CHS" : "EDD");
+ printf("cache_data: %p\n", dev->cache_data);
+ printf("cache_head: %p\n", dev->cache_head);
+ printf("cache_block_size: %d\n", dev->cache_block_size);
+ printf("cache_entries: %d\n", dev->cache_entries);
+ printf("cache_size: %d\n", dev->cache_size);
+}
+
/*
* it will do:
* initialize the device structure;
int blk_shift;
struct fs_ops *ops = (struct fs_ops*)regs->eax.l;
- device_init(&dev, regs->edx.b[0], regs->edx.b[1], regs->ecx.l);
+ device_init(&dev, regs->edx.b[0], regs->ecx.l);
/* set up the fs stucture */
fs.fs_name = ops->fs_name;
this_fs = &fs;
/* invoke the fs-specific init code */
- blk_shift = fs.fs_ops->fs_init();
-
+ blk_shift = fs.fs_ops->fs_init();
+
/* initialize the cache */
if (dev.cache_data)
- cache_init(&dev, blk_shift);
+ cache_init(&dev, blk_shift);
}