Update of /cvsroot/blob/blob/src/blob In directory usw-pr-cvs1:/tmp/cvs-serv27294/src/blob Modified Files: Makefile.am main.c Added Files: compr_rtime.c compr_rubin.c compr_zlib.c cramfs.c jffs2.c load_kernel.c mini_inflate.c zImage.c Log Message: most of Russ's jffs2 code updated --- NEW FILE: compr_rtime.c --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by Arjan van de Ven <ar...@re...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_rtime.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * * * Very simple lz77-ish encoder. * * Theory of operation: Both encoder and decoder have a list of "last * occurances" for every possible source-value; after sending the * first source-byte, the second byte indicated the "run" length of * matches * * The algorithm is intended to only send "whole bytes", no bit-messing. * */ #include "blob/types.h" void rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen) { int positions[256]; int outpos; int pos; int i; outpos = pos = 0; for (i = 0; i < 256; positions[i++] = 0); while (outpos<destlen) { unsigned char value; int backoffs; int repeat; value = data_in[pos++]; cpage_out[outpos++] = value; /* first the verbatim copied byte */ repeat = data_in[pos++]; backoffs = positions[value]; positions[value]=outpos; if (repeat) { if (backoffs + repeat >= outpos) { while(repeat) { cpage_out[outpos++] = cpage_out[backoffs++]; repeat--; } } else { for (i = 0; i < repeat; i++) *(cpage_out + outpos + i) = *(cpage_out + backoffs + i); outpos+=repeat; } } } } --- NEW FILE: compr_rubin.c --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by Arjan van de Ven <ar...@re...> * * Heavily modified by Russ Dill <Rus...@as...> in an attempt at * a little more speed. * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_rubin.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * */ #include "blob/types.h" #include "blob/compr_rubin.h" void rubin_do_decompress(unsigned char *bits, unsigned char *in, unsigned char *page_out, u32 destlen) { register char *curr = page_out; char *end = page_out + destlen; register unsigned long temp; register unsigned long result; register unsigned long p; register unsigned long q; register unsigned long rec_q; register unsigned long bit; register long i0; unsigned long i; /* init_pushpull */ temp = *(u32 *) in; bit = 16; /* init_rubin */ q = 0; p = (long) (2 * UPPER_BIT_RUBIN); /* init_decode */ rec_q = (in[0] << 8) | in[1]; while (curr < end) { /* in byte */ result = 0; for (i = 0; i < 8; i++) { /* decode */ while ((q & UPPER_BIT_RUBIN) || ((p + q) <= UPPER_BIT_RUBIN)) { q &= ~UPPER_BIT_RUBIN; q <<= 1; p <<= 1; rec_q &= ~UPPER_BIT_RUBIN; rec_q <<= 1; rec_q |= (temp >> (bit++ ^ 7)) & 1; if (bit > 31) { bit = 0; temp = *(++((u32 *) in)); } } i0 = (bits[i] * p) >> 8; if (i0 <= 0) i0 = 1; /* if it fails, it fails, we have our crc if (i0 >= p) i0 = p - 1; */ result >>= 1; if (rec_q < q + i0) { /* result |= 0x00; */ p = i0; } else { result |= 0x80; p -= i0; q += i0; } } *(curr++) = result; } } void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, unsigned long sourcelen, unsigned long dstlen) { unsigned char bits[8]; int c; for (c=0; c<8; c++) bits[c] = (256 - data_in[c]); rubin_do_decompress(bits, data_in+8, cpage_out, dstlen); } --- NEW FILE: compr_zlib.c --- /* * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dw...@ca...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: compr_zlib.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * */ #include "blob/types.h" #include "blob/load_kernel.h" #include "blob/mini_inflate.h" void zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen) { decompress_block(cpage_out, data_in + 2, ldr_memcpy); } --- NEW FILE: cramfs.c --- /*------------------------------------------------------------------------- * Filename: cramfs.c * Version: $Id: cramfs.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Rus...@as...> * Description: Module to load kernel from a cramfs *-----------------------------------------------------------------------*/ /* * * 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 * */ /* note: this module doesn't currently support symlinks, but because of the * nature of cramfs, this shouldn't be a big deal */ #include "blob/types.h" #include "blob/load_kernel.h" #include "blob/mini_inflate.h" #define CRAMFS_MAGIC 0x28cd3d45 /* some random number */ struct cramfs_inode { /* sizeof == 12*/ u32 mode:16, uid:16; /* SIZE for device files is i_rdev */ u32 size:24, gid:8; /* NAMELEN is the length of the file name, divided by 4 and rounded up. (cramfs doesn't support hard links.) */ /* OFFSET: For symlinks and non-empty regular files, this contains the offset (divided by 4) of the file data in compressed form (starting with an array of block pointers; see README). For non-empty directories it is the offset (divided by 4) of the inode of the first file in that directory. For anything else, offset is zero. */ u32 namelen:6, offset:26; }; /* * Superblock information at the beginning of the FS. */ struct cramfs_super { /* sizeof == 62 == 0x40 + 12 */ u32 magic; /* 0x28cd3d45 - random number */ u32 size; /* Not used. mkcramfs currently writes a constant 1<<16 here. */ u32 flags; /* 0 */ u32 future; /* 0 */ u8 signature[16]; /* "Compressed ROMFS" */ u8 fsid[16]; /* random number */ u8 name[16]; /* user-defined name */ struct cramfs_inode root; /* Root inode data */ }; static int cramfs_check_magic(struct part_info *part) { return *((u32 *) part->offset) == CRAMFS_MAGIC; } static long cramfs_uncompress_page(char *dest, char *src, u32 srclen) { long size; src++; /* *src == 0x78 method */ src++; /* *src == 0x9C flags (!PRESET_DICT) */ size = decompress_block(dest, src, ldr_memcpy); return size; } static long cramfs_load_file(u32 *dest, struct part_info *part, struct cramfs_inode *inode) { long int curr_block; unsigned long *block_ptrs; long size, total_size = 0; int i; ldr_update_progress(); block_ptrs = ((u32 *) part->offset) + inode->offset; curr_block = (inode->offset + ((inode->size + 4095) >> 12)) << 2; for (i = 0; i < ((inode->size + 4095) >> 12); i++) { size = cramfs_uncompress_page((char *) dest, curr_block + part->offset, block_ptrs[i] - curr_block); if (size < 0) return size; ((char *) dest) += size; /* Print a '.' every 0x40000 bytes */ if (((total_size + size) & ~0x3ffff) - (total_size & ~0x3ffff)) ldr_update_progress(); total_size += size; curr_block = block_ptrs[i]; } return total_size; } static u32 cramfs_load_kernel(u32 *dest, struct part_info *part) { struct cramfs_super *super; struct cramfs_inode *inode; unsigned long next_inode; char *name; long size; size = -1; super = (struct cramfs_super *) part->offset; next_inode = super->root.offset << 2; while (next_inode < (super->root.offset << 2) + super->root.size) { inode = (struct cramfs_inode *) (next_inode + part->offset); next_inode += (inode->namelen << 2) + sizeof(struct cramfs_inode); if (!(inode->mode & 0x8000)) continue; /* Is it a file? */ /* does it have 5 to 8 characters? */ if (!inode->namelen == 2) continue; name = (char *) (inode + 1); if (!ldr_strncmp("linux\0\0", name, 8)) { size = cramfs_load_file(dest, part, inode); break; } } return size <= 0 ? 0 : size; } struct kernel_loader cramfs_load = { check_magic: cramfs_check_magic, load_kernel: cramfs_load_kernel, name: "cramfs" }; --- NEW FILE: jffs2.c --- /* ------------------------------------------------------------------------- * Filename: jffs2.c * Version: $Id: jffs2.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Rus...@as...> * Description: Module to load kernel from jffs2 *-----------------------------------------------------------------------*/ /* * some portions of this code are taken from jffs2, and as such, the * following copyright notice is included. * * JFFS2 -- Journalling Flash File System, Version 2. * * Copyright (C) 2001 Red Hat, Inc. * * Created by David Woodhouse <dw...@ca...> * * The original JFFS, from which the design for JFFS2 was derived, * was designed and implemented by Axis Communications AB. * * The contents of this file are subject to the Red Hat eCos Public * License Version 1.1 (the "Licence"); you may not use this file * except in compliance with the Licence. You may obtain a copy of * the Licence at http://www.redhat.com/ * * Software distributed under the Licence is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. * See the Licence for the specific language governing rights and * limitations under the Licence. * * The Original Code is JFFS2 - Journalling Flash File System, version 2 * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License version 2 (the "GPL"), in * which case the provisions of the GPL are applicable instead of the * above. If you wish to allow the use of your version of this file * only under the terms of the GPL and not to allow others to use your * version of this file under the RHEPL, indicate your decision by * deleting the provisions above and replace them with the notice and * other provisions required by the GPL. If you do not delete the * provisions above, a recipient may use your version of this file * under either the RHEPL or the GPL. * * $Id: jffs2.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * */ /* Ok, so anyone who knows the jffs2 code will probably want to get a papar * bag to throw up into before reading this code. I looked through the jffs2 * code, the caching scheme is very elegant. I tried to keep the version * for a bootloader as small and simple as possible. Instead of worring about * unneccesary data copies, node scans, etc, I just optimized for the known * common case, a kernel, which looks like: * (1) most pages are 4096 bytes * (2) version numbers are somewhat sorted in acsending order * (3) multiple compressed blocks making up one page is uncommon * * So I create a linked list of decending version numbers (insertions at the * head), and then for each page, walk down the list, until a matching page * with 4096 bytes is found, and then decompress the watching pages in * reverse order. * */ #include "blob/types.h" #include "blob/load_kernel.h" #include "blob/jffs2.h" #include "blob/crc32.h" static struct jffs2_raw_dirent *find_inode(struct part_info *part, char *name, u32 pino); void rtime_decompress (unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen); void dynrubin_decompress(unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen); void zlib_decompress (unsigned char *data_in, unsigned char *cpage_out, u32 srclen, u32 destlen); struct data_strip { struct jffs2_raw_inode *inode; long int version; long int page; long int length; struct data_strip *next; }; inline int hdr_crc(struct jffs2_unknown_node *node) { if(node->hdr_crc != crc32(0, node, sizeof(struct jffs2_unknown_node) - 4)) return 0; else return 1; } inline int dirent_crc(struct jffs2_raw_dirent *node) { if (node->node_crc != crc32(0, node, sizeof(struct jffs2_raw_dirent) - 8)) { UDEBUG("bad dirent_crc\n"); return 0; } else return 1; } inline int dirent_name_crc(struct jffs2_raw_dirent *node) { if (node->name_crc != crc32(0, &(node->name), node->nsize)) { UDEBUG("bad dirent_name_crc\n"); return 0; } else return 1; } inline int inode_crc(struct jffs2_raw_inode *node) { if (node->node_crc != crc32(0, node, sizeof(struct jffs2_raw_inode) - 8)) { UDEBUG("bad inode_crc\n"); return 0; } else return 1; } /* decompress a page from the flash, first contains a linked list of references * all the nodes of this file, sorted is decending order (newest first) */ static int jffs2_uncompress_page(char *dest, struct data_strip *first, u32 page) { int i; char *src; /* look for the next reference to this page */ for (; first && first->page != page; first = first->next); if (!first) return 1; /* if we aren't covering what's behind us, uncompress that first */ if (first->length != 4096) if (!(jffs2_uncompress_page(dest, first->next, page))) return 0; dest += first->inode->offset; src = ((char *) first->inode) + sizeof(struct jffs2_raw_inode); if (first->inode->data_crc != crc32(0, src, first->inode->csize)) { ldr_output_string("CRC Error!"); return 0; } switch (first->inode->compr) { case JFFS2_COMPR_NONE: ldr_memcpy(dest, src, first->length); break; case JFFS2_COMPR_ZERO: for (i = 0; i < first->length; i++) *(dest++) = 0; break; case JFFS2_COMPR_RTIME: rtime_decompress(src, dest, first->inode->csize, first->length); break; case JFFS2_COMPR_DYNRUBIN: dynrubin_decompress(src, dest, first->inode->csize, first->length); break; case JFFS2_COMPR_ZLIB: zlib_decompress(src, dest, first->inode->csize, first->length); break; default: /* unknown */ } return 1; } static int jffs2_check_magic(struct part_info *part) { unsigned long offset; struct jffs2_unknown_node *node; /* search the start of each erase block for a magic number */ offset = 0; for (offset = 0; offset < part->size; offset += part->erasesize) { node = (struct jffs2_unknown_node *) (part->offset + offset); if (node->magic == JFFS2_MAGIC_BITMASK && hdr_crc(node)) return 1; } return 0; } /* read in the data for inode inode_num */ static u32 read_inode(struct part_info *part, u32 *dest, u32 inode_num, int type) { unsigned long size; struct jffs2_raw_inode *inode; unsigned long offset, inode_version, version, page; struct data_strip *free, *curr, *prev, *first, *new; free = (struct data_strip *) fodder_ram_base; first = NULL; offset = size = inode_version = 0; /* Fill the list of nodes pertaining to this file */ while (offset < part->size - sizeof(struct jffs2_raw_inode)) { inode = (struct jffs2_raw_inode *) (part->offset + offset); if (inode->magic == JFFS2_MAGIC_BITMASK && hdr_crc(inode)) { if (inode->nodetype == JFFS2_NODETYPE_INODE && inode->ino == inode_num && inode_crc(inode)) { /* add it in newest first order to our list */ prev = NULL; curr = first; version = inode->version; while (curr && curr->version > version) { prev = curr; curr = curr->next; } new = free++; new->version = version; new->inode = inode; new->page = (inode->offset / 4096); new->length = inode->dsize; if (!prev) { new->next = first; first = new; } else { new->next = prev->next; prev->next = new; } if (version > inode_version) { inode_version = version; size = type == DT_LNK ? inode->dsize : inode->isize; } } offset += ((inode->totlen + 3) & ~3); } else offset += 4; } if (!first) UDEBUG("could not find any nodes!\n"); for (page = 0; page <= size / 4096; page++) { /* Print a '.' every 0x40000 bytes */ if (!(page & 0x3F)) ldr_update_progress(); if ((jffs2_uncompress_page((char *) dest, first, page)) <= 0) { UDEBUG("jffs2_uncompress_page failed on page 0x%lx\n", page); return 0; } } return size; } /* follow a symlink */ static struct jffs2_raw_dirent *do_symlink(struct part_info *part, struct jffs2_raw_dirent *node) { char name[JFFS2_MAX_NAME_LEN + 1]; unsigned long size; UDEBUG(" finding symlink "); /* read in the symlink */ if((size = read_inode(part, (u32 *) name, node->ino, DT_LNK))) { name[size] = '\0'; UDEBUG(" '%s'\n", name); /* if it points to /, start over at inode 1, otherwise, stay * in the same directory */ if (name[0] == '/') return find_inode(part, name + 1, 1); else return find_inode(part, name, node->pino); } else { UDEBUG("could not load symlink!"); return NULL; } } /* find a dirent with the name "name", and parent "pino" return NULL on * error */ static struct jffs2_raw_dirent *find_inode(struct part_info *part, char *name, u32 pino) { char curr_name[JFFS2_MAX_NAME_LEN + 1]; int len, i, up = 0; struct jffs2_raw_dirent *node, *curr; unsigned long version, off; i = 0; do { /* parse the next dir/file/symlink */ len = 0; while (name[i] != '\0' && name[i] != '/') curr_name[len++] = name[i++]; curr_name[len] = '\0'; /* go up an inode if its a '..' */ up = (len == 2 && !ldr_strncmp("..", curr_name, 2)); UDEBUG("\nlooking for '%s' ...", curr_name); /* start again...at the beginning */ version = off = 0; node = NULL; while (off < part->size - sizeof(struct jffs2_raw_inode)) { curr = (struct jffs2_raw_dirent *)(part->offset + off); if (curr->magic == JFFS2_MAGIC_BITMASK && hdr_crc(curr)) { if (curr->nodetype == JFFS2_NODETYPE_DIRENT && up && curr->ino == pino && dirent_crc(curr) && curr->version > version) { version = curr->version; node = curr; } else if (curr->nodetype == JFFS2_NODETYPE_DIRENT && !up && curr->pino == pino && curr->nsize == len && dirent_crc(curr) && dirent_name_crc(curr) && !ldr_strncmp(curr_name, curr->name, len) && curr->version > version) { UDEBUG("found matching dirent\n"); version = curr->version; node = curr; } off += (curr->totlen + 3) & ~3; } else off += 4; } if (!node) return NULL; if (node->type == DT_LNK) if (!(node = do_symlink(part, node))) return NULL; /* if we are going up a dir, we want to look for the parent */ if (up) { pino = node->pino; up = 0; } else pino = node->ino; UDEBUG(" '%s' found at ino %ld\n", curr_name, pino); } while (name[i++] == '/'); return node; } static u32 jffs2_load_kernel(u32 *dest, struct part_info *part) { struct jffs2_raw_dirent *node; if (!(node = find_inode(part, "linux", 1))) { UDEBUG("could not find /linux\n"); return 0; } if (node->type != DT_REG) { UDEBUG("/linux is not a regular file\n"); return 0; } return read_inode(part, dest, node->ino, DT_REG); } struct kernel_loader jffs2_load = { check_magic: jffs2_check_magic, load_kernel: jffs2_load_kernel, name: "jffs2" }; --- NEW FILE: load_kernel.c --- /*------------------------------------------------------------------------- * Filename: load_kernel.c * Version: $Id: load_kernel.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Rus...@as...> * Description: interface between kernel loaders and boot loader. if everything was done right, this *should be the only file that needs changing for porting to different boot loaders. *-----------------------------------------------------------------------*/ /* * * 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 * */ #include "types.h" #include "load_kernel.h" #include "config.h" #include "serial.h" #include "util.h" #include "main.h" #ifdef CONFIG_CRAMFS_SUPPORT extern struct kernel_loader cramfs_load; #endif #ifdef CONFIG_ZIMAGE_SUPPORT extern struct kernel_loader zImage_load; #endif #ifdef CONFIG_JFFS2_SUPPORT extern struct kernel_loader jffs2_load; #endif #define FODDER_RAM_BASE (0xC0F00000) const struct kernel_loader *loader[] = { #ifdef CONFIG_CRAMFS_SUPPORT &cramfs_load, #endif #ifdef CONFIG_ZIMAGE_SUPPORT &zImage_load, #endif #ifdef CONFIG_JFFS2_SUPPORT &jffs2_load, #endif NULL }; const void *fodder_ram_base = (void *) FODDER_RAM_BASE; /* function calls for blob */ inline void ldr_update_progress(void) { printf("."); } inline int ldr_strncmp(char *a, char *b, size_t n) { return strncmp(a, b, n); } inline void *ldr_memcpy(void *dst, void *src, size_t n) { memcpy(dst, src, n); return dst; } inline void ldr_output_string(char *str) { SerialOutputString(str); } inline void ldr_output_hex(u32 hex) { SerialOutputHex(hex); } --- NEW FILE: mini_inflate.c --- /*------------------------------------------------------------------------- * Filename: mini_inflate.c * Version: $Id: mini_inflate.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Rus...@as...> * Description: Mini inflate implementation (RFC 1951) *-----------------------------------------------------------------------*/ /* * * 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 * */ #include "blob/mini_inflate.h" /* The order that the code lengths in section 3.2.7 are in */ static unsigned char huffman_order[] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; inline void cramfs_memset(int *s, const int c, size n) { n--; for (;n > 0; n--) s[n] = c; s[0] = c; } /* associate a stream with a block of data and reset the stream */ static void init_stream(struct bitstream *stream, unsigned char *data, void *(*inflate_memcpy)(void *, void *, size)) { stream->error = NO_ERROR; stream->memcpy = inflate_memcpy; stream->decoded = 0; stream->data = data; stream->bit = 0; /* The first bit of the stream is the lsb of the * first byte */ /* really sorry about all this initialization, think of a better way, * let me know and it will get cleaned up */ stream->codes.bits = 8; stream->codes.num_symbols = 19; stream->codes.lengths = stream->code_lengths; stream->codes.symbols = stream->code_symbols; stream->codes.count = stream->code_count; stream->codes.first = stream->code_first; stream->codes.pos = stream->code_pos; stream->lengths.bits = 16; stream->lengths.num_symbols = 288; stream->lengths.lengths = stream->length_lengths; stream->lengths.symbols = stream->length_symbols; stream->lengths.count = stream->length_count; stream->lengths.first = stream->length_first; stream->lengths.pos = stream->length_pos; stream->distance.bits = 16; stream->distance.num_symbols = 32; stream->distance.lengths = stream->distance_lengths; stream->distance.symbols = stream->distance_symbols; stream->distance.count = stream->distance_count; stream->distance.first = stream->distance_first; stream->distance.pos = stream->distance_pos; } /* pull 'bits' bits out of the stream. The last bit pulled it returned as the * msb. (section 3.1.1) */ inline unsigned long pull_bits(struct bitstream *stream, const unsigned int bits) { unsigned long ret; int i; ret = 0; for (i = 0; i < bits; i++) { ret += ((*(stream->data) >> stream->bit) & 1) << i; /* if, before incrementing, we are on bit 7, * go to the lsb of the next byte */ if (stream->bit++ == 7) { stream->bit = 0; stream->data++; } } return ret; } inline int pull_bit(struct bitstream *stream) { int ret = ((*(stream->data) >> stream->bit) & 1); if (stream->bit++ == 7) { stream->bit = 0; stream->data++; } return ret; } /* discard bits up to the next whole byte */ static void discard_bits(struct bitstream *stream) { if (stream->bit != 0) { stream->bit = 0; stream->data++; } } /* No decompression, the data is all literals (section 3.2.4) */ static void decompress_none(struct bitstream *stream, unsigned char *dest) { unsigned int length; discard_bits(stream); length = *(stream->data++); length += *(stream->data++) << 8; pull_bits(stream, 16); /* throw away the inverse of the size */ stream->decoded += length; stream->memcpy(dest, stream->data, length); stream->data += length; } /* Read in a symbol from the stream (section 3.2.2) */ static int read_symbol(struct bitstream *stream, struct huffman_set *set) { int bits = 0; int code = 0; while (!(set->count[bits] && code < set->first[bits] + set->count[bits])) { code = (code << 1) + pull_bit(stream); if (++bits > set->bits) { /* error decoding (corrupted data?) */ stream->error = CODE_NOT_FOUND; return -1; } } return set->symbols[set->pos[bits] + code - set->first[bits]]; } /* decompress a stream of data encoded with the passed length and distance * huffman codes */ static void decompress_huffman(struct bitstream *stream, unsigned char *dest) { struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); int symbol, length, dist, i; do { if ((symbol = read_symbol(stream, lengths)) < 0) return; if (symbol < 256) { *(dest++) = symbol; /* symbol is a literal */ stream->decoded++; } else if (symbol > 256) { /* Determine the length of the repitition * (section 3.2.5) */ if (symbol < 265) length = symbol - 254; else if (symbol == 285) length = 258; else { length = pull_bits(stream, (symbol - 261) >> 2); length += (4 << ((symbol - 261) >> 2)) + 3; length += ((symbol - 1) % 4) << ((symbol - 261) >> 2); } /* Determine how far back to go */ if ((symbol = read_symbol(stream, distance)) < 0) return; if (symbol < 4) dist = symbol + 1; else { dist = pull_bits(stream, (symbol - 2) >> 1); dist += (2 << ((symbol - 2) >> 1)) + 1; dist += (symbol % 2) << ((symbol - 2) >> 1); } stream->decoded += length; for (i = 0; i < length; i++) *(dest++) = dest[-dist]; } } while (symbol != 256); /* 256 is the end of the data block */ } /* Fill the lookup tables (section 3.2.2) */ static void fill_code_tables(struct huffman_set *set) { int code = 0, i, length; /* fill in the first code of each bit length, and the pos pointer */ set->pos[0] = 0; for (i = 1; i < set->bits; i++) { code = (code + set->count[i - 1]) << 1; set->first[i] = code; set->pos[i] = set->pos[i - 1] + set->count[i - 1]; } /* Fill in the table of symbols in order of their huffman code */ for (i = 0; i < set->num_symbols; i++) { if ((length = set->lengths[i])) set->symbols[set->pos[length]++] = i; } /* reset the pos pointer */ for (i = 1; i < set->bits; i++) set->pos[i] -= set->count[i]; } static void init_code_tables(struct huffman_set *set) { cramfs_memset(set->lengths, 0, set->num_symbols); cramfs_memset(set->count, 0, set->bits); cramfs_memset(set->first, 0, set->bits); } /* read in the huffman codes for dynamic decoding (section 3.2.7) */ static void decompress_dynamic(struct bitstream *stream, unsigned char *dest) { /* I tried my best to minimize the memory footprint here, while still * keeping up performance. I really dislike the _lengths[] tables, but * I see no way of eliminating them without a sizable performance * impact. The first struct table keeps track of stats on each bit * length. The _length table keeps a record of the bit length of each * symbol. The _symbols table is for looking up symbols by the huffman * code (the pos element points to the first place in the symbol table * where that bit length occurs). I also hate the initization of these * structs, if someone knows how to compact these, lemme know. */ struct huffman_set *codes = &(stream->codes); struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); int hlit = pull_bits(stream, 5) + 257; int hdist = pull_bits(stream, 5) + 1; int hclen = pull_bits(stream, 4) + 4; int length, curr_code, symbol, i, last_code; last_code = 0; init_code_tables(codes); init_code_tables(lengths); init_code_tables(distance); /* fill in the count of each bit length' as well as the lengths * table */ for (i = 0; i < hclen; i++) { length = pull_bits(stream, 3); codes->lengths[huffman_order[i]] = length; if (length) codes->count[length]++; } fill_code_tables(codes); /* Do the same for the length codes, being carefull of wrap through * to the distance table */ curr_code = 0; while (curr_code < hlit) { if ((symbol = read_symbol(stream, codes)) < 0) return; if (symbol == 0) { curr_code++; last_code = 0; } else if (symbol < 16) { /* Literal length */ lengths->lengths[curr_code] = last_code = symbol; lengths->count[symbol]++; curr_code++; } else if (symbol == 16) { /* repeat the last symbol 3 - 6 * times */ length = 3 + pull_bits(stream, 2); for (;length; length--, curr_code++) if (curr_code < hlit) { lengths->lengths[curr_code] = last_code; lengths->count[last_code]++; } else { /* wrap to the distance table */ distance->lengths[curr_code - hlit] = last_code; distance->count[last_code]++; } } else if (symbol == 17) { /* repeat a bit length 0 */ curr_code += 3 + pull_bits(stream, 3); last_code = 0; } else { /* same, but more times */ curr_code += 11 + pull_bits(stream, 7); last_code = 0; } } fill_code_tables(lengths); /* Fill the distance table, don't need to worry about wrapthrough * here */ curr_code -= hlit; while (curr_code < hdist) { if ((symbol = read_symbol(stream, codes)) < 0) return; if (symbol == 0) { curr_code++; last_code = 0; } else if (symbol < 16) { distance->lengths[curr_code] = last_code = symbol; distance->count[symbol]++; curr_code++; } else if (symbol == 16) { length = 3 + pull_bits(stream, 2); for (;length; length--, curr_code++) { distance->lengths[curr_code] = last_code; distance->count[last_code]++; } } else if (symbol == 17) { curr_code += 3 + pull_bits(stream, 3); last_code = 0; } else { curr_code += 11 + pull_bits(stream, 7); last_code = 0; } } fill_code_tables(distance); decompress_huffman(stream, dest); } /* fill in the length and distance huffman codes for fixed encoding * (section 3.2.6) */ static void decompress_fixed(struct bitstream *stream, unsigned char *dest) { /* let gcc fill in the initial values */ struct huffman_set *lengths = &(stream->lengths); struct huffman_set *distance = &(stream->distance); cramfs_memset(lengths->count, 0, 16); cramfs_memset(lengths->first, 0, 16); cramfs_memset(lengths->lengths, 8, 144); cramfs_memset(lengths->lengths + 144, 9, 112); cramfs_memset(lengths->lengths + 256, 7, 24); cramfs_memset(lengths->lengths + 280, 8, 8); lengths->count[7] = 24; lengths->count[8] = 152; lengths->count[9] = 112; cramfs_memset(distance->count, 0, 16); cramfs_memset(distance->first, 0, 16); cramfs_memset(distance->lengths, 5, 32); distance->count[5] = 32; fill_code_tables(lengths); fill_code_tables(distance); decompress_huffman(stream, dest); } /* returns the number of bytes decoded, < 0 if there was an error. Note that * this function assumes that the block starts on a byte boundry * (non-compliant, but I don't see where this would happen). section 3.2.3 */ long decompress_block(unsigned char *dest, unsigned char *source, void *(*inflate_memcpy)(void *, void *, size)) { int bfinal, btype; struct bitstream stream; init_stream(&stream, source, inflate_memcpy); do { bfinal = pull_bit(&stream); btype = pull_bits(&stream, 2); if (btype == NO_COMP) decompress_none(&stream, dest + stream.decoded); else if (btype == DYNAMIC_COMP) decompress_dynamic(&stream, dest + stream.decoded); else if (btype == FIXED_COMP) decompress_fixed(&stream, dest + stream.decoded); else stream.error = COMP_UNKNOWN; } while (!bfinal && !stream.error); return stream.error ? -stream.error : stream.decoded; } --- NEW FILE: zImage.c --- /*------------------------------------------------------------------------- * Filename: zimage.c * Version: $Id: zImage.c,v 1.1 2002/02/14 09:59:34 timriker Exp $ * Copyright: Copyright (C) 2001, Russ Dill * Author: Russ Dill <Rus...@as...> * Description: Module to load kernel straight from flash *-----------------------------------------------------------------------*/ /* * * 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 * */ #include "blob/types.h" #include "blob/load_kernel.h" #define ZIMAGE_MAGIC 0x016f2818 static int zImage_check_magic(struct part_info *part) { return ((u32 *) part->offset)[9] == ZIMAGE_MAGIC; } static u32 zImage_load_kernel(u32 *dest, struct part_info *part) { unsigned long size; int i; size = ((u32 *) part->offset)[11] - ((u32 *) part->offset)[10]; /* yes, it could be copied all at once, but I wanted to call * ldr_update_progress */ for (i = 0; i <= size - 0x40000; i += 0x40000) { ldr_update_progress(); ldr_memcpy((char *) dest + i, part->offset + i, 0x40000); } ldr_memcpy((char *) dest + i, part->offset + i, size - i); return size; } struct kernel_loader zImage_load = { check_magic: zImage_check_magic, load_kernel: zImage_load_kernel, name: "zImage" }; Index: Makefile.am =================================================================== RCS file: /cvsroot/blob/blob/src/blob/Makefile.am,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- Makefile.am 7 Feb 2002 22:56:22 -0000 1.22 +++ Makefile.am 14 Feb 2002 09:59:34 -0000 1.23 @@ -48,8 +48,6 @@ $(CC) -x c-header -undef -nostdinc ${INCLUDES} -E $< | sed 's/^#.*//' > $@ - - # ---- Blob first stage loader --------------------------------------- # WARNING: start.S *must* be the first file, otherwise the target will @@ -136,7 +134,15 @@ partition.c \ reboot.c \ uucodec.c \ - xmodem.c + xmodem.c \ + load_kernel.c \ + mini_inflate.c \ + jffs2.c \ + compr_rtime.c \ + compr_rubin.c \ + compr_zlib.c \ + cramfs.c \ + zImage.c # conditionally compiled sources Index: main.c =================================================================== RCS file: /cvsroot/blob/blob/src/blob/main.c,v retrieving revision 1.31 retrieving revision 1.32 diff -u -d -r1.31 -r1.32 --- main.c 8 Feb 2002 12:55:16 -0000 1.31 +++ main.c 14 Feb 2002 09:59:34 -0000 1.32 @@ -57,7 +57,7 @@ #include <blob/uucodec.h> #include <blob/xmodem.h> - +#include "load_kernel.h" static int do_reload(char *what); @@ -70,8 +70,39 @@ blob_status_t blob_status; static char *version_str = PACKAGE " version " VERSION " for " BOARD_NAME "\n"; +void load_kernel(blob_status_t *blob_status) +{ + int i; + unsigned long size; + struct part_info part; - +/* FIXME this is hardcoded, should use flash[].size */ +#define MAIN_BLOCK_SIZE 2 * 64 * 1024 + part.erasesize = MAIN_BLOCK_SIZE; + part.size = KERNEL_FLASH_LEN; + part.offset = (char *) KERNEL_FLASH_BASE; + for (i = 0; loader[i] && !loader[i]->check_magic(&part); i++); + if (!loader[i]) { + SerialOutputString("unable to find kernel, loading raw data " + "and hoping for the best!\rloading"); + size = KERNEL_FLASH_LEN; + MyMemCpy((u32 *)KERNEL_RAM_BASE, (u32 *)KERNEL_FLASH_BASE, size >> 2); + + } else { + SerialOutputString("loading kernel from "); + SerialOutputString(loader[i]->name); + if ((size = loader[i]->load_kernel((u32 *)KERNEL_RAM_BASE, + &part)) == 0) { + SerialOutputString(" error loading kernel!\r"); + return; + } + } + SerialOutputString("loaded 0x"); + SerialOutputHex(size); + SerialOutputString(" bytes\r"); + blob_status->kernelSize = size; + blob_status->kernelType = fromFlash; +} int main(void) { |