Core: Convert linsector and open_inode function to C
authorLiu Aleaxander <Aleaxander@gmail.com>
Thu, 4 Jun 2009 23:29:20 +0000 (07:29 +0800)
committerLiu Aleaxander <Aleaxander@gmail.com>
Thu, 4 Jun 2009 23:29:20 +0000 (07:29 +0800)
The two functions are converted to C.
And for another thing, I find that I haven't included the load_config.c file before(my fault),
so added it here.

core/cache.c
core/cache.h
core/ext2.c
core/extern.inc
core/extlinux.asm
core/load_config.c [new file with mode: 0644]

index 2e65172..b3f2316 100644 (file)
@@ -74,12 +74,11 @@ void cache_init(com32sys_t * regs)
  * @return: the data stores at gs:si
  *
  */
-void get_cache_block(com32sys_t * regs)
+struct cache_struct* get_cache_block(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 *head,  *last;
-    block_t block = regs->eax.l;
     int i;
 
     static int total_read;
@@ -90,8 +89,8 @@ void get_cache_block(com32sys_t * regs)
 #endif
 
     if ( !block ) {
-        myputs("ERROR: we got a ZERO block number that's not we want!\n");
-        return;
+        printf("ERROR: we got a ZERO block number that's not we want!\n");
+        return NULL;
     }
     
     /* it's aleardy the freshest, so nothing we need do , just return it */
@@ -139,6 +138,5 @@ void get_cache_block(com32sys_t * regs)
     if ( (char *)(cs->data) > (char*)0x100000 )
         printf("the buffer addres higher than 1M limit\n\r");
     
-    regs->gs = SEG(cs->data);
-    regs->esi.w[0]= OFFS(cs->data);
+    return cs;
 }    
index b47cc5c..65df6cd 100644 (file)
@@ -19,6 +19,6 @@ struct cache_struct {
 /* functions defined in cache.c */
 void cache_init(com32sys_t *regs);
 
-void get_cache_block(com32sys_t *regs);
+struct cache_struct* get_cache_block(block_t);
 
 #endif /* cache.h */
index 3cd2782..28606ee 100644 (file)
 #include <stdio.h>
 #include <string.h>
+#include "cache.h"
 #include "core.h"
 #include "disk.h"
 #include "ext2_fs.h"
 
 
+#define MAX_OPEN_LG2     6
+#define MAX_OPEN         (1 << MAX_OPEN_LG2)
+
+/* 
+ * File structure, This holds the information for each currently open file 
+ */
+struct open_file_t {
+        uint32_t file_bytesleft;  /* Number of bytes left (0 = free) */
+        uint32_t file_sector;     /* Next linear sector to read */
+        uint32_t file_in_sec;     /* Sector where inode lives */
+        uint16_t file_in_off;
+        uint16_t file_mode;
+};
+
+extern char Files[MAX_OPEN * sizeof(struct open_file_t)];
+
+
+extern char ThisInode[128];
+struct ext2_inode *this_inode = ThisInode;
+
+extern uint16_t ClustByteShift,  ClustShift;
+extern uint32_t SecPerClust, ClustSize, ClustMask;
+extern uint32_t PtrsPerBlock1, PtrsPerBlock2;
+uint32_t PtrsPerBlock3;
+
+int DescPerBlock, InodePerBlock;
+
+struct ext2_super_block *sb;    
+
+
+
+/**
+ * allocate_file:
+ * 
+ * Allocate a file structure
+ *
+ * @return: if successful return the file pointer, or return NULL
+ *
+ */
+struct open_file_t *allocate_file()
+{
+    struct open_file_t *file = (struct open_file_t *)Files;
+    int i = 0;
+        
+    for (; i < MAX_OPEN; i ++) {
+        if (file->file_bytesleft == 0) /* found it */
+            return file;
+        file ++;
+    }
+    
+    return NULL; /* not found */
+}
+
+
+/**
+ * get_group_desc:
+ *
+ * get the group's descriptor of group_num
+ *
+ * @param: group_num, the group number;
+ * 
+ * @return: the pointer of the group's descriptor
+ *
+ */ 
+struct ext2_group_desc *get_group_desc(uint32_t group_num)
+{
+    block_t block_num;
+    uint32_t offset;
+    struct ext2_group_desc *desc;
+    struct cache_struct *cs;
+
+    block_num = group_num / DescPerBlock;
+    offset = group_num % DescPerBlock;
+
+    block_num += sb->s_first_data_block + 1;
+    cs = get_cache_block(block_num);
+
+    desc = (struct ext2_group_desc *)cs->data + offset;
+
+    return desc;
+}
+
+
+/**
+ * read_inode:
+ *
+ * read the right inode structure to _dst_.
+ *
+ * @param: inode_offset, the inode offset within a group;
+ * @prarm: dst, wher we will store the inode structure;
+ * @param: desc, the pointer to the group's descriptor
+ * @param: block, a pointer used for retruning the blk number for file structure
+ * @param: offset, same as block
+ *
+ */
+void read_inode(uint32_t inode_offset, 
+                struct ext2_inode *dst, struct ext2_group_desc *desc,
+                block_t *block, uint32_t *offset)
+{
+    struct cache_struct *cs;
+    struct ext2_inode *inode;
+    
+    *block  = inode_offset / InodePerBlock + desc->bg_inode_table;
+    *offset = inode_offset % InodePerBlock;
+    
+    cs = get_cache_block(*block);
+    
+    /* well, in EXT4, the inode structure usually be 256 */
+    inode = (struct ext2_inode *)(cs->data + (*offset * (sb->s_inode_size)));
+    memcpy(dst, inode, EXT2_GOOD_OLD_INODE_SIZE);
+    
+    /* for file structure */
+    *offset = (inode_offset * sb->s_inode_size) % ClustSize;
+}
+
+
+/**
+ * open_inode:
+ *
+ * open a file indicated by an inode number in INR
+ *
+ * @param : regs, regs->eax stores the inode number
+ * @return: a open_file_t structure pointer, stores in regs->esi
+ *          file length in bytes, stores in regs->eax
+ *          the first 128 bytes of the inode, stores in ThisInode
+ *
+ */
+void open_inode(com32sys_t *regs)
+{
+    uint32_t inr = regs->eax.l;
+    uint32_t file_len;
+
+    struct open_file_t *file;
+    struct ext2_group_desc *desc;
+        
+    uint32_t inode_group, inode_offset;
+    block_t block_num;
+    uint32_t block_off;    
+    
+    file = allocate_file();
+    if (!file)
+        goto err;
+    
+    file->file_sector = 0;
+    
+    inr --;
+    inode_group  = inr / sb->s_inodes_per_group;
+    
+    /* get the group desc */
+    desc = get_group_desc(inode_group);
+    
+    inode_offset = inr % sb->s_inodes_per_group;
+    read_inode(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);
+    file->file_in_off = block_off & (SECTOR_SIZE - 1);
+    file->file_mode = this_inode->i_mode;
+    file_len = file->file_bytesleft = this_inode->i_size;
+    
+    if (file_len == 0)
+        goto err;
+    
+    regs->esi.w[0] = file;
+    regs->eax.l = file_len;
+    return;
+
+ err:
+    regs->eax.l = 0;
+}
+
+
+
+struct ext4_extent_header * 
+ext4_find_leaf (struct ext4_extent_header *eh, block_t block)
+{
+    struct ext4_extent_idx *index;
+    struct cache_struct *cs;
+    uint64_t blk;
+    int i;
+    
+    while (1) {        
+        if (eh->eh_magic != EXT4_EXT_MAGIC)
+            return NULL;
+        
+        /* got it */
+        if (eh->eh_depth == 0)
+            return eh;
+        
+        index = EXT4_FIRST_INDEX(eh);        
+        for ( i = 0; i < eh->eh_entries; i++ ) {
+            if ( block < index[i].ei_block )
+                break;
+        }
+        if ( --i < 0 )
+            return NULL;
+        
+        blk = index[i].ei_leaf_hi;
+        blk = (blk << 32) + index[i].ei_leaf_lo;
+        
+        /* read the blk to memeory */
+        cs = get_cache_block(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)
+{
+    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);
+    if (! leaf) {
+        printf("ERROR, extent leaf not found\n");
+        return 0;
+    }
+    
+    ext = EXT4_FIRST_EXTENT(leaf);
+    for ( i = 0; i < leaf->eh_entries; i++ ) {
+        if ( block < ext[i].ee_block)
+            break;
+    }
+    if ( --i < 0 ) {
+        printf("ERROR, not find the right block\n");
+        return 0;
+    }
+    
+    
+    /* got it */
+    block -= ext[i].ee_block;
+    if ( block >= ext[i].ee_len)
+        return 0;
+    
+    start = ext[i].ee_start_hi;
+    start = (start << 32) + ext[i].ee_start_lo;
+    
+    return start + block;
+}
+
+
+/**
+ * linsector_direct:
+ * 
+ * @param: block, the block index
+ * @param: inode, the inode structure
+ *
+ * @return: the physic block number
+ */
+block_t linsector_direct(block_t block, struct ext2_inode *inode)
+{
+    struct cache_struct *cs;
+    
+    /* direct blocks */
+    if (block < EXT2_NDIR_BLOCKS) 
+        return inode->i_block[block];
+    
+
+    /* indirect blocks */
+    block -= EXT2_NDIR_BLOCKS;
+    if (block < PtrsPerBlock1) {
+        block_t ind_block = inode->i_block[EXT2_IND_BLOCK];
+        cs = get_cache_block(ind_block);
+        
+        return ((block_t *)cs->data)[block];
+    }
+    
+    /* double indirect blocks */
+    block -= PtrsPerBlock1;
+    if (block < PtrsPerBlock2) {
+        block_t dou_block = inode->i_block[EXT2_DIND_BLOCK];
+        cs = get_cache_block(dou_block);
+        
+        dou_block = ((block_t *)cs->data)[block / PtrsPerBlock1];
+        cs = get_cache_block(dou_block);
+        
+        return ((block_t*)cs->data)[block % PtrsPerBlock1];
+    }
+    
+    /* triple indirect block */
+    block -= PtrsPerBlock2;
+    if (block < PtrsPerBlock3) {
+        block_t tri_block = inode->i_block[EXT2_TIND_BLOCK];
+        cs = get_cache_block(tri_block);
+        
+        tri_block = ((block_t *)cs->data)[block / PtrsPerBlock2];
+        cs = get_cache_block(tri_block);
+        
+        tri_block = ((block_t *)cs->data)[block % PtrsPerBlock2];
+        cs = get_cache_block(tri_block);
+
+        return ((uint32_t*)cs->data)[block % PtrsPerBlock1];
+    }
+    
+    /* File too big, can not handle */
+    printf("ERROR, file too big\n");
+    return 0;
+}
+
+
+/**
+ * linsector:
+ *
+ * Convert a linear sector index in a file to linear sector number
+ *
+ * well, alought this function converts a linear sector number to 
+ * physic sector number, it uses block cache in the implemention.
+ * 
+ * @param: lin_sector, the lineral sector index
+ * 
+ * @return: physic sector number
+ */
+void linsector(com32sys_t *regs)
+{
+    sector_t lin_sector = regs->eax.l;
+    block_t block = lin_sector >> ClustShift;
+    struct ext2_inode *inode;
+
+    /* well, this is what I think the variable this_inode used for */
+    inode = this_inode;
+
+    if (inode->i_flags & EXT4_EXTENTS_FLAG)
+        block = linsector_extent(block, inode);
+    else
+        block = (uint32_t)linsector_direct(block, inode);
+    
+    if (!block) {
+        printf("ERROR: something error happend at linsector..\n");
+        regs->eax.l = 0;
+        return;
+    }
+    
+    /* finally convert it to sector */
+    regs->eax.l = ((block << ClustShift) + (lin_sector & ClustMask));
+}
+
+
 
 /**
  * init. the fs meta data, return the block size in eax
  */
 void init_fs(com32sys_t *regs)
 {
-    extern uint16_t ClustByteShift,  ClustShift;
-    extern uint32_t SecPerClust, ClustSize, ClustMask;
-    extern uint32_t PtrsPerBlock1, PtrsPerBlock2;
     extern char SuperBlock[1024];
-    struct ext2_super_block *sb;    
     
     /* read the super block */
     read_sectors(SuperBlock, 2, 2);
@@ -25,15 +361,15 @@ void init_fs(com32sys_t *regs)
     ClustSize = 1 << ClustByteShift;
     ClustShift = ClustByteShift - SECTOR_SHIFT;
     
-    //DescPerBlock  = ClustSize >> ext2_group_desc_lg2size;
-    //InodePerBlock = ClustSize / sb->s_inode_size;
+    DescPerBlock  = ClustSize >> ext2_group_desc_lg2size;
+    InodePerBlock = ClustSize / sb->s_inode_size;
         
     SecPerClust = ClustSize >> SECTOR_SHIFT;
     ClustMask = SecPerClust - 1;
     
     PtrsPerBlock1 = 1 << ( ClustByteShift - 2 );
     PtrsPerBlock2 = 1 << ( (ClustByteShift - 2) * 2);
-    //PtrsPerBlock3 = 1 << ( (ClustByteShift - 2) * 3);
+    PtrsPerBlock3 = 1 << ( (ClustByteShift - 2) * 3);
     
-    regs->eax.l = SECTOR_SHIFT;
+    regs->eax.l = ClustByteShift;
 }
index 58c5c96..c8288fe 100644 (file)
        extern hello
 
        ; cache.c
-       extern cache_init, get_cache_block
+       extern cache_init
 
        ; load_config.c
        extern load_config
 
        ; ext2.c
-       extern init_fs
+       extern init_fs, linsector, open_inode
 
 %endif ; EXTERN_INC
index 0c0b404..e4e0fed 100644 (file)
@@ -104,6 +104,7 @@ ClustShift  resb 1                  ; Shift count for sectors/cluster
 ClustByteShift resb 1                  ; Shift count for bytes/cluster
 
                alignb open_file_t_size
+               global Files
 Files          resb MAX_OPEN*open_file_t_size
 
 ;
@@ -194,123 +195,11 @@ getlinsec_ext:
                jnz getlinsec_ext
                ret
 
-;
-; allocate_file: Allocate a file structure
-;
-;              If successful:
-;                ZF set
-;                BX = file pointer
-;              In unsuccessful:
-;                ZF clear
-;
-allocate_file:
-               TRACER 'a'
-               push cx
-               mov bx,Files
-               mov cx,MAX_OPEN
-.check:                cmp dword [bx], byte 0
-               je .found
-               add bx,open_file_t_size         ; ZF = 0
-               loop .check
-               ; ZF = 0 if we fell out of the loop
-.found:                pop cx
-               ret
-;
-; open_inode:
-;           Open a file indicated by an inode number in EAX
-;
-;           NOTE: This file considers finding a zero-length file an
-;           error.  This is so we don't have to deal with that special
-;           case elsewhere in the program (most loops have the test
-;           at the end).
-;
-;           If successful:
-;              ZF clear
-;              SI          = file pointer
-;              EAX         = file length in bytes
-;              ThisInode   = the first 128 bytes of the inode
-;           If unsuccessful
-;              ZF set
-;
-;           Assumes CS == DS == ES.
-;
-open_inode.allocate_failure:
-               xor eax,eax
-               pop bx
-               pop di
-               ret
-
-open_inode:
-               push di
-               push bx
-               call allocate_file
-               jnz .allocate_failure
-
-               push cx
-               push gs
-               ; First, get the appropriate inode group and index
-               dec eax                         ; There is no inode 0
-               xor edx,edx
-               mov [bx+file_sector],edx
-               div dword [SuperBlock+s_inodes_per_group]
-               ; EAX = inode group; EDX = inode within group
-               push edx
 
-               ; Now, we need the block group descriptor.
-               ; To get that, we first need the relevant descriptor block.
-
-               shl eax, ext2_group_desc_lg2size ; Get byte offset in desc table
-               xor edx,edx
-               div dword [ClustSize]
-               ; eax = block #, edx = offset in block
-               add eax,dword [SuperBlock+s_first_data_block]
-               inc eax                         ; s_first_data_block+1
-               mov cl,[ClustShift]
-               shl eax,cl
-               push edx
-               shr edx,SECTOR_SHIFT
-               add eax,edx
-               pop edx
-               and dx,SECTOR_SIZE-1
-               pm_call get_cache_block         ; Get the group descriptor
-               add si,dx
-               mov esi,[gs:si+bg_inode_table]  ; Get inode table block #
-               pop eax                         ; Get inode within group
-               movzx edx, word [SuperBlock+s_inode_size]
-               mul edx
-               ; edx:eax = byte offset in inode table
-               div dword [ClustSize]
-               ; eax = block # versus inode table, edx = offset in block
-               add eax,esi
-               shl eax,cl                      ; Turn into sector
-               push dx
-               shr edx,SECTOR_SHIFT
-               add eax,edx
-               mov [bx+file_in_sec],eax
-               pop dx
-               and dx,SECTOR_SIZE-1
-               mov [bx+file_in_off],dx
-
-               pm_call get_cache_block
-               add si,dx
-               mov cx,EXT2_GOOD_OLD_INODE_SIZE >> 2
-               mov di,ThisInode
-               gs rep movsd
-
-               mov ax,[ThisInode+i_mode]
-               mov [bx+file_mode],ax
-               mov eax,[ThisInode+i_size]
-               mov [bx+file_bytesleft],eax
-               mov si,bx
-               and eax,eax                     ; ZF clear unless zero-length file
-               pop gs
-               pop cx
-               pop bx
-               pop di
-               ret
 
                section .bss16
                alignb 4
+               global ThisInode
 ThisInode      resb EXT2_GOOD_OLD_INODE_SIZE   ; The most recently opened inode
 
                section .text16
@@ -365,7 +254,7 @@ searchdir:
 .open:
                push eax                ; Save directory inode
 
-               call open_inode
+               pm_call open_inode
                jz .missing             ; If error, done
 
                mov cx,[si+file_mode]
@@ -635,113 +524,6 @@ kaboom2:
 .noreg:                jmp short .noreg        ; Nynorsk
 
 
-;
-; linsector:   Convert a linear sector index in a file to a linear sector number
-;      EAX     -> linear sector number
-;      DS:SI   -> open_file_t
-;
-;              Returns next sector number in EAX; CF on EOF (not an error!)
-;
-linsector:
-               push gs
-               push ebx
-               push esi
-               push edi
-               push ecx
-               push edx
-               push ebp
-
-               push eax                ; Save sector index
-               mov cl,[ClustShift]
-               shr eax,cl              ; Convert to block number
-               push eax
-               mov eax,[si+file_in_sec]
-               mov bx,si
-               pm_call get_cache_block ; Get inode
-               add si,[bx+file_in_off] ; Get *our* inode
-               pop eax
-               lea ebx,[i_block+4*eax]
-               cmp eax,EXT2_NDIR_BLOCKS
-               jb .direct
-               mov ebx,i_block+4*EXT2_IND_BLOCK
-               sub eax,EXT2_NDIR_BLOCKS
-               mov ebp,[PtrsPerBlock1]
-               cmp eax,ebp
-               jb .ind1
-               mov ebx,i_block+4*EXT2_DIND_BLOCK
-               sub eax,ebp
-               mov ebp,[PtrsPerBlock2]
-               cmp eax,ebp
-               jb .ind2
-               mov ebx,i_block+4*EXT2_TIND_BLOCK
-               sub eax,ebp
-
-.ind3:
-               ; Triple indirect; eax contains the block no
-               ; with respect to the start of the tind area;
-               ; ebx contains the pointer to the tind block.
-               xor edx,edx
-               div dword [PtrsPerBlock2]
-               ; EAX = which dind block, EDX = pointer within dind block
-               push ax
-               shr eax,SECTOR_SHIFT-2
-               mov ebp,[gs:si+bx]
-               shl ebp,cl
-               add eax,ebp
-               pm_call get_cache_block
-               pop bx
-               and bx,(SECTOR_SIZE >> 2)-1
-               shl bx,2
-               mov eax,edx             ; The ind2 code wants the remainder...
-
-.ind2:
-               ; Double indirect; eax contains the block no
-               ; with respect to the start of the dind area;
-               ; ebx contains the pointer to the dind block.
-               xor edx,edx
-               div dword [PtrsPerBlock1]
-               ; EAX = which ind block, EDX = pointer within ind block
-               push ax
-               shr eax,SECTOR_SHIFT-2
-               mov ebp,[gs:si+bx]
-               shl ebp,cl
-               add eax,ebp
-               pm_call get_cache_block
-               pop bx
-               and bx,(SECTOR_SIZE >> 2)-1
-               shl bx,2
-               mov eax,edx             ; The int1 code wants the remainder...
-
-.ind1:
-               ; Single indirect; eax contains the block no
-               ; with respect to the start of the ind area;
-               ; ebx contains the pointer to the ind block.
-               push ax
-               shr eax,SECTOR_SHIFT-2
-               mov ebp,[gs:si+bx]
-               shl ebp,cl
-               add eax,ebp
-               pm_call get_cache_block
-               pop bx
-               and bx,(SECTOR_SIZE >> 2)-1
-               shl bx,2
-
-.direct:
-               mov ebx,[gs:bx+si]      ; Get the pointer
-
-               pop eax                 ; Get the sector index again
-               shl ebx,cl              ; Convert block number to sector
-               and eax,[ClustMask]     ; Add offset within block
-               add eax,ebx
-
-               pop ebp
-               pop edx
-               pop ecx
-               pop edi
-               pop esi
-               pop ebx
-               pop gs
-               ret
 
 ;
 ; getfssec: Get multiple sectors from a file
@@ -774,7 +556,7 @@ getfssec:
 .getfragment:
                mov eax,[si+file_sector]        ; Current start index
                mov edi,eax
-               call linsector
+               pm_call linsector
                push eax                        ; Fragment start sector
                mov edx,eax
                xor ebp,ebp                     ; Fragment sector count
@@ -794,7 +576,7 @@ getfssec:
                inc edi                         ; Sector index
                inc edx                         ; Linearly next sector
                mov eax,edi
-               call linsector
+               pm_call linsector
                ; jc .do_read
                cmp edx,eax
                je .getseccnt
diff --git a/core/load_config.c b/core/load_config.c
new file mode 100644 (file)
index 0000000..2c81946
--- /dev/null
@@ -0,0 +1,26 @@
+#include <stdio.h>
+#include <string.h>
+
+#include "core.h"
+
+
+void 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
+}