From: Tim R. <tim...@us...> - 2002-04-26 04:47:02
|
Update of /cvsroot/blob/blob/src/lib In directory usw-pr-cvs1:/tmp/cvs-serv29979/src/lib Modified Files: Makefile.am Added Files: disk.c Log Message: get ready for reading vfat --- NEW FILE: disk.c --- /* * disk.c * * read extfs file system root dir, locate image and load it into memory * * this is a very large hack which assumes: * - ms-dos partion table * - linux partition is #1 partition * - bootable image is at /zImage or /boot/zImage * - ramdisk image is at /ramdisk.gz or /boot/ramdisk.gz * * Copyright (C) 2001, Brad Parker (br...@he...) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H # include <blob/config.h> #endif #include <blob/serial.h> #include <blob/util.h> #include <blob/serial.h> #define _SIZE_T /* don't use the one in the kernel's types.h */ #include <linux/ext2_fs.h> char buf1[512], buf2[512]; char sb_block_buf[EXT2_MAX_BLOCK_SIZE]; char inode_block_buf[EXT2_MAX_BLOCK_SIZE]; char dir_block_buf[EXT2_MAX_BLOCK_SIZE]; char ind_block_buf[EXT2_MAX_BLOCK_SIZE]; char ind2_block_buf[EXT2_MAX_BLOCK_SIZE]; char block1[EXT2_MAX_BLOCK_SIZE]; char block2[EXT2_MAX_BLOCK_SIZE]; extern int verbose; extern int hd_read_mapped(int sector_num, char *buffer); char tohex(char b) { b = b & 0xf; if (b < 10) return '0' + b; return 'a' + (b - 10); } void dumpmem(char *ptr, int len) { char line[80], chars[80], *p, b, *c, *end; int j; end = ptr + len; while (ptr < end) { SerialOutputHex((int)ptr); p = line; c = chars; *p++ = ' '; for (j = 0; j < 16; j++) { b = *ptr++; *p++ = tohex(b >> 4); *p++ = tohex(b); *p++ = ' '; *c++ = ' ' <= b && b <= '~' ? b : '.'; } *p = 0; SerialOutputString(line); *c = 0; SerialOutputString(chars); serial_write('\n'); } } #ifdef TEST char disk[1024*1024*8]; int read_buffer(int sectornum, char *buf) { char *ptr = disk + sectornum * 512; if (ptr > disk+sizeof(disk)) { printf("read past eod!\n"); while (1); return -1; } memcpy(buf, ptr, 512); return 0; } #else int read_buffer(int sectornum, char *buf) { return hd_read_mapped(sectornum, buf); } #endif void debug(char *msg) { printf("%s\n", msg); } int le32_p(u8 *p) { int n; n = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; return n; } /* ms-dos disk partition structure */ struct part_ent { u8 p_boot; u8 p_start[3]; u8 p_type; u8 p_end[3]; u8 p_start_sector[4]; u8 p_size_sectors[4]; }; static unsigned int start, size; static unsigned int base; struct ext2_group_desc group_desc[32]; unsigned int boot_inode_num=0; unsigned int our_inode_num=0; unsigned int e2fs_block_size; unsigned int e2fs_sectors_per_block; void set_ext2fs_block_size(int bytes) { e2fs_block_size = bytes; e2fs_sectors_per_block = bytes / 512; if (verbose > 1) { printf("set_ext2fs_block_size(bytes=%d) sectors_per_block %d\n", bytes, e2fs_sectors_per_block); } } /* read ext2fs 4k block */ int read_block(int blocknum, char *buf) { unsigned int abs_blocknum = base + blocknum*e2fs_sectors_per_block; int i; if (verbose > 2) printf("read_block(%d) base %d, abs %d\n", blocknum, base, abs_blocknum); for (i = 0; i < e2fs_sectors_per_block; i++) { if (read_buffer(abs_blocknum, buf) != 0) { return -1; } abs_blocknum++; buf += 512; } return 0; } /* check master boot record; locate parition info */ int check_mbr() { struct part_ent *p; int h, s, c; if( verbose > 0) printf("check MBR...\n"); if (read_buffer(0, buf1)) { debug("mbr read error"); return -1; } if ((u8)buf1[510] != 0x55 || (u8)buf1[511] != 0xaa) { debug("bad mbr signature"); if (verbose > 1) dumpmem(buf1, sizeof(buf1)); return -1; } /* XXX 1st partition must be linux */ p = (struct part_ent *)&buf1[0x1be]; if (p->p_type != 0x83) { debug("part #1 not linux"); return -1; } h = p->p_start[0]; s = p->p_start[1] & 0x3f; c = ((p->p_start[1] & 0xc0) << 2) + p->p_start[2]; if( verbose > 0) printf("found linux partition\n"); start = le32_p(p->p_start_sector); size = le32_p(p->p_size_sectors); if (verbose > 1) { printf("partition @ h=%d,s=%d,c=%d\n", h, s, c); printf("start %d, size %d\n", start, size); } return 0; } /* * read ext2fs inode * require group descriptors to be in memory */ int read_inode(struct ext2_super_block *sb, int ino, struct ext2_inode *ibuf) { unsigned long group, offset, block, block_nr; group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb); block = offset >> EXT2_BLOCK_SIZE_BITS(sb); if (!group_desc[(unsigned)group].bg_inode_table) { if( verbose > 0) { printf("inode %d; group %d, offset %d, block %d; no group descriptor\n", ino, group, offset, block); } return -1; } block_nr = group_desc[(unsigned)group].bg_inode_table + block; offset &= (EXT2_BLOCK_SIZE(sb) - 1); if (verbose > 1) { printf("inode %d; group %d, offset %d, block %d, block_nr %d\n", ino, group, offset, block, block_nr); printf("inodes/group %d, inode size %d\n", EXT2_INODES_PER_GROUP(sb), EXT2_INODE_SIZE(sb)); } /* read entire block and copy inode out */ if (read_block(block_nr, inode_block_buf)) return -1; memcpy((char *)ibuf, inode_block_buf + offset, 128); return 0; } int load_indirect_block(int iblock_num, char **pptr, unsigned long *poffset) { int i; u8 *p; unsigned long bn; char *ptr; unsigned long offset; ptr = *pptr; offset = *poffset; if (verbose > 1) printf("indirect block %d\n", iblock_num); if (read_block(iblock_num, ind_block_buf)) { debug("read indirect block error"); return -1; } p = ind_block_buf; for (i = 0; i < e2fs_block_size/4; i++) { bn = le32_p(p); p += 4; if (bn == 0) break; #if 0 // FIXME if (verbose > 2) printf("file block # %d (0x%x)\n", bn, bn); else if( verbose > 0) printf("%d \r", offset); #endif // 0 FIXME switch( verbose) { case 0: if( bn % 100 == 0) serial_write( '.'); break; case 1: printf("%d \r", offset); break; default: printf("file block # %d (0x%x)\n", bn, bn); break; } if (read_block(bn, ptr)) { debug("read file block error"); return -1; } ptr += e2fs_sectors_per_block*512; offset += e2fs_sectors_per_block*512; } *pptr = ptr; *poffset = offset; return 0; } int load_file_inode(struct ext2_super_block *sb, unsigned int inode_num, char *ptr) { struct ext2_inode file_inode, *inode; unsigned long offset; int i; if (read_inode(sb, inode_num, &file_inode)) { debug("read file inode error"); return -1; } inode = &file_inode; offset = 0; if (verbose > 1) { printf("file inode:\n"); printf("mode %o\n", inode->i_mode); printf("flags %x\n", inode->i_flags); printf("size %x\n", inode->i_size); printf("blocks %x (max %d)\n", inode->i_blocks, EXT2_N_BLOCKS); } for (i = 0; i < EXT2_NDIR_BLOCKS; i++) { if (verbose > 1) printf("block[%d] %d (0%x)\n", i, inode->i_block[i], inode->i_block[i]); else if( verbose > 0) printf("%d \r", offset); else if( inode->i_block[i] % 100 == 0) serial_write( '.'); if (inode->i_block[i] == 0) break; if (read_block(inode->i_block[i], ptr)) { debug("read file block error"); return -1; } ptr += e2fs_sectors_per_block*512; offset += e2fs_sectors_per_block*512; } if (inode->i_block[EXT2_NDIR_BLOCKS]) { if (verbose > 2) printf("1 indirect block %d\n", inode->i_block[EXT2_NDIR_BLOCKS]); if (load_indirect_block(inode->i_block[EXT2_NDIR_BLOCKS], &ptr, &offset)) return -1; } if (inode->i_block[EXT2_NDIR_BLOCKS+1]) { int i; u8 *p; unsigned long bn; if (verbose > 2) printf("2 indirect block %d\n", inode->i_block[EXT2_NDIR_BLOCKS+1]); if (read_block(inode->i_block[EXT2_NDIR_BLOCKS+1], ind2_block_buf)) { debug("read 2nd indirect block error"); return -1; } p = ind2_block_buf; for (i = 0; i < e2fs_block_size/4; i++) { bn = le32_p(p); p += 4; if (bn == 0) break; if (verbose > 2) printf("ind block # %d (0x%x)\n", bn, bn); if (load_indirect_block(bn, &ptr, &offset)) return -1; } } #if 0 if (inode->i_block[EXT2_NDIR_BLOCKS+2]) { printf("3 indirect inode %d\n", inode->i_block[EXT2_NDIR_BLOCKS+2]); if(read_block(inode->i_block[EXT2_NDIR_BLOCKS+2], &ind_block_buf)) { debug("read 3rd indirect block error"); return -1; } } #endif if( verbose > 0) printf("done! offset %d (0x%x)\n", offset, offset); else serial_write( '\n'); return inode->i_size; // success: return file size } /* * read file "fileName" into RAM location ramBase */ int load_root_image(char *fileName, void *ramBase) { struct ext2_super_block *sb; struct ext2_inode root_inode, boot_inode, *inode; struct ext2_group_desc *bg; struct ext2_dir_entry_2 *de; int sb_block, group_block, group_desc_count, desc_blocks; int i; unsigned long offset; int retval=0; /* read super block */ base = start; sb_block = 1; group_block = sb_block + 1; if( verbose > 0) printf("reading super block...\n"); set_ext2fs_block_size(1024); #if 0 { int abn; abn = base; for (i = 0; i < 8; i++) { printf("abn %d\n", abn); if (read_buffer(abn, sb_block_buf) != 0) break; dumpmem(sb_block_buf, 64); abn++; } } #endif if (read_block(sb_block, sb_block_buf)) { debug("find_root read error"); return -1; } sb = (struct ext2_super_block *)sb_block_buf; if (verbose > 1) printf("sb magic %x\n", sb->s_magic); if (sb->s_magic != EXT2_SUPER_MAGIC) { debug("sb magic number wrong"); return -1; } if (verbose > 1) { printf("block size %d\n", EXT2_BLOCK_SIZE(sb)); printf("blocks per group %d\n", sb->s_blocks_per_group); printf("block # of sb %d\n", sb->s_block_group_nr); printf("first data block %d\n", sb->s_first_data_block); printf("inodes / group %d\n", EXT2_INODES_PER_GROUP(sb)); } group_desc_count = (sb->s_blocks_count - sb->s_first_data_block + EXT2_BLOCKS_PER_GROUP(sb) - 1) / EXT2_BLOCKS_PER_GROUP(sb); desc_blocks = (group_desc_count + EXT2_DESC_PER_BLOCK(sb) - 1) / EXT2_DESC_PER_BLOCK(sb); if (verbose > 1) printf("group_block %d, group_desc_count %d, desc_blocks %d\n", group_block, group_desc_count, desc_blocks); /* set block size */ set_ext2fs_block_size(EXT2_BLOCK_SIZE(sb)); //this is wrong and a hack; why? if (EXT2_BLOCK_SIZE(sb) == 4096) group_block = 1; /* read group descriptors */ if (read_block(group_block, block2)) { debug("read group desc error"); return -1; } if (verbose > 4) { dumpmem(block2, sizeof(block2)); } bg = (struct ext2_group_desc *)block2; for (i = 0; i < group_desc_count; i++) { group_desc[i] = bg[i]; if (verbose > 1) { printf("block group %d\n", i); printf("dirs %d\n", bg[i].bg_used_dirs_count); } } // set_ext2fs_block_size(EXT2_BLOCK_SIZE(sb)); /* read root inode */ if (read_inode(sb, EXT2_ROOT_INO, &root_inode)) { debug("read initial inode error"); return -1; } inode = &root_inode; if (verbose > 1) { printf("mode %o\n", inode->i_mode); printf("flags %x\n", inode->i_flags); printf("size %x\n", inode->i_size); printf("blocks %x (max %d)\n", inode->i_blocks, EXT2_N_BLOCKS); printf("block[0] %x\n", inode->i_block[0]); printf("block[1] %x\n", inode->i_block[1]); printf("\n"); } if (read_block(inode->i_block[0], dir_block_buf)) { debug("read root inode dir block error"); return -1; } if (verbose > 1) printf("scanning root dir\n"); offset = 0; while (offset < 4096) { char name[256]; de = (struct ext2_dir_entry_2 *)(dir_block_buf + offset); if (verbose > 1) printf("offset 0x%x, len 0x%x\n", offset, de->rec_len); strncpy(name, de->name, de->name_len); name[de->name_len] = 0; offset += de->rec_len; if (verbose > 1) { printf("inode %d, type %d, name '%s'\n", de->inode, de->file_type, name); printf("rec_len %d (%x), b %d\n", de->rec_len, de->rec_len, offset); } if (/* FIXME de->file_type == 2 && */ strncmp(name, "boot", 5) == 0) { if( verbose > 0) printf("found /boot dir\n"); if (verbose > 1) printf("/boot dir inode %d\n", de->inode); boot_inode_num = de->inode; break; } // FIXME de->file_type == 0 for me 8-( if (/* FIXME de->file_type == 1 && */ strncmp(name, fileName, sizeof(name)) == 0) { if( verbose > 0) printf("found /%s\n", fileName); if (verbose > 1) printf("/%s inode %d\n", fileName, de->inode); our_inode_num = de->inode; break; } } if (boot_inode_num) { if (verbose > 1) printf("scanning /boot dir\n"); if (read_inode(sb, boot_inode_num, &boot_inode)) { debug("read boot inode error"); return -1; } inode = &boot_inode; if (verbose > 1) { printf("mode %o\n", inode->i_mode); printf("flags %x\n", inode->i_flags); printf("size %x\n", inode->i_size); printf("blocks %x\n", inode->i_blocks); printf("block[0] %x\n", inode->i_block[0]); printf("block[1] %x\n", inode->i_block[1]); } if (read_block(inode->i_block[0], dir_block_buf)) { debug("read boot inode dir block error"); return -1; } our_inode_num = 0; offset = 0; while (offset < 4096) { char name[256]; de = (struct ext2_dir_entry_2 *)(dir_block_buf + offset); strncpy(name, de->name, de->name_len); name[de->name_len] = 0; offset += de->rec_len; if (verbose > 1) { printf("inode %d, type %d, name '%s'\n", de->inode, de->file_type, name); printf("rec_len %d (%x), b %d\n", de->rec_len, de->rec_len, offset); } if (/* FIXME de->file_type == 1 && */ strncmp(name, fileName, sizeof(name)) == 0) { printf("found /boot/%s\n", fileName); our_inode_num = de->inode; } if (our_inode_num) break; } } if (our_inode_num) { if( verbose > 0) printf("reading %s:\n", fileName); if( (retval=load_file_inode(sb, our_inode_num, ramBase)) < 0) return -1; } return retval; // success: return file size } #ifdef TEST main() { int fd; fd = open("/tmp/disk", 0); read(fd, disk, sizeof(disk)); close(fd); check_mbr(); find_root(); } #endif Index: Makefile.am =================================================================== RCS file: /cvsroot/blob/blob/src/lib/Makefile.am,v retrieving revision 1.16 retrieving revision 1.17 diff -u -d -r1.16 -r1.17 --- Makefile.am 19 Apr 2002 19:59:23 -0000 1.16 +++ Makefile.am 26 Apr 2002 04:46:59 -0000 1.17 @@ -25,14 +25,13 @@ libblob.a -# no headers, so these are broken -# ide.c \ -# pcmcia.c \ libblob_a_SOURCES = \ command.c \ crc32.c \ + disk.c \ error.c \ icache.c \ + ide.c \ init.c \ led.c \ md5.c \ @@ -40,6 +39,7 @@ memcpy.c \ memset.c \ mini_inflate.c \ + pcmcia.c \ printf.c \ reboot.c \ serial.c \ |