src/system/mtdutils: Add files from mtd-utils

- based on mtd-utils http://git.infradead.org/mtd-utils.git
 commit ab8c6fb93ce9db0f09401c4b819b0b277dc00340 (2013-07-01)
- Add files for create jffs2 image and using sumtool
- Creating classes for mkfs.jffs2 and sumtool


Origin commit data
------------------
Commit: d8957d17ac
Author: Michael Liebmann <tuxcode.bbg@gmail.com>
Date: 2013-09-01 (Sun, 01 Sep 2013)

Origin message was:
------------------
src/system/mtdutils: Add files from mtd-utils

- based on mtd-utils http://git.infradead.org/mtd-utils.git
 commit ab8c6fb93ce9db0f09401c4b819b0b277dc00340 (2013-07-01)
- Add files for create jffs2 image and using sumtool
- Creating classes for mkfs.jffs2 and sumtool
This commit is contained in:
Michael Liebmann
2013-09-01 17:57:41 +02:00
parent 1a4b568ceb
commit d87eeae5ce
33 changed files with 9672 additions and 0 deletions

340
src/system/mtdutils/COPYING Normal file
View File

@@ -0,0 +1,340 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
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
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.

View File

@@ -0,0 +1,538 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory
* in the jffs2 directory.
*/
#include "compr.h"
#include <string.h>
#include <stdlib.h>
#include <linux/jffs2.h>
#define FAVOUR_LZO_PERCENT 80
extern int page_size;
/* LIST IMPLEMENTATION (from linux/list.h) */
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
static inline void __list_add(struct list_head *new_,
struct list_head *prev,
struct list_head *next)
{
next->prev = new_;
new_->next = next;
new_->prev = prev;
prev->next = new_;
}
static inline void list_add(struct list_head *new_, struct list_head *head)
{
__list_add(new_, head, head->next);
}
static inline void list_add_tail(struct list_head *new_, struct list_head *head)
{
__list_add(new_, head->prev, head);
}
static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = NULL;
entry->prev = NULL;
}
#define list_entry(ptr, type, member) \
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member))
/* Available compressors are on this_ list */
static LIST_HEAD(jffs2_compressor_list);
/* Actual compression mode */
static int jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
void jffs2_set_compression_mode(int mode)
{
jffs2_compression_mode = mode;
}
int jffs2_get_compression_mode(void)
{
return jffs2_compression_mode;
}
/* Statistics for blocks stored without compression */
static uint32_t none_stat_compr_blocks=0,none_stat_decompr_blocks=0,none_stat_compr_size=0;
/* Compression test stuffs */
static int jffs2_compression_check = 0;
static unsigned char *jffs2_compression_check_buf = NULL;
void jffs2_compression_check_set(int yesno)
{
jffs2_compression_check = yesno;
}
int jffs2_compression_check_get(void)
{
return jffs2_compression_check;
}
static int jffs2_error_cnt = 0;
int jffs2_compression_check_errorcnt_get(void)
{
return jffs2_error_cnt;
}
#define JFFS2_BUFFER_FILL 0x55
/* Called before compression (if compression_check is setted) to prepare
the buffer for buffer overflow test */
static void jffs2_decompression_test_prepare(unsigned char *buf, int size)
{
memset(buf,JFFS2_BUFFER_FILL,size+1);
}
/* Called after compression (if compression_check is setted) to test the result */
static void jffs2_decompression_test(struct jffs2_compressor *compr,
unsigned char *data_in, unsigned char *output_buf,
uint32_t cdatalen, uint32_t datalen, uint32_t buf_size)
{
uint32_t i;
/* buffer overflow test */
for (i=buf_size;i>cdatalen;i--) {
if (output_buf[i]!=JFFS2_BUFFER_FILL) {
fprintf(stderr,"COMPR_ERROR: buffer overflow at %s. "
"(bs=%d csize=%d b[%d]=%d)\n", compr->name,
buf_size, cdatalen, i, (int)(output_buf[i]));
jffs2_error_cnt++;
return;
}
}
/* allocing temporary buffer for decompression */
if (!jffs2_compression_check_buf) {
jffs2_compression_check_buf = (unsigned char*)malloc(page_size);
if (!jffs2_compression_check_buf) {
fprintf(stderr,"No memory for buffer allocation. Compression check disabled.\n");
jffs2_compression_check = 0;
return;
}
}
/* decompressing */
if (!compr->decompress) {
fprintf(stderr,"JFFS2 compression check: there is no decompress function at %s.\n", compr->name);
jffs2_error_cnt++;
return;
}
if (compr->decompress(output_buf,jffs2_compression_check_buf,cdatalen,datalen)) {
fprintf(stderr,"JFFS2 compression check: decompression failed at %s.\n", compr->name);
jffs2_error_cnt++;
}
/* validate decompression */
else {
for (i=0;i<datalen;i++) {
if (data_in[i]!=jffs2_compression_check_buf[i]) {
fprintf(stderr,"JFFS2 compression check: data mismatch at %s (pos %d).\n", compr->name, i);
jffs2_error_cnt++;
break;
}
}
}
}
/*
* Return 1 to use this_ compression
*/
static int jffs2_is_best_compression(struct jffs2_compressor *this_,
struct jffs2_compressor *best, uint32_t size, uint32_t bestsize)
{
switch (jffs2_compression_mode) {
case JFFS2_COMPR_MODE_SIZE:
if (bestsize > size)
return 1;
return 0;
case JFFS2_COMPR_MODE_FAVOURLZO:
if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > size))
return 1;
if ((best->compr != JFFS2_COMPR_LZO) && (bestsize > size))
return 1;
if ((this_->compr == JFFS2_COMPR_LZO) && (bestsize > (size * FAVOUR_LZO_PERCENT / 100)))
return 1;
if ((bestsize * FAVOUR_LZO_PERCENT / 100) > size)
return 1;
return 0;
}
/* Shouldn't happen */
return 0;
}
/* jffs2_compress:
* @data: Pointer to uncompressed data
* @cdata: Pointer to returned pointer to buffer for compressed data
* @datalen: On entry, holds the amount of data available for compression.
* On exit, expected to hold the amount of data actually compressed.
* @cdatalen: On entry, holds the amount of space available for compressed
* data. On exit, expected to hold the actual size of the compressed
* data.
*
* Returns: Lower byte to be stored with data indicating compression type used.
* Zero is used to show that the data could not be compressed - the
* compressed version was actually larger than the original.
* Upper byte will be used later. (soon)
*
* If the cdata buffer isn't large enough to hold all the uncompressed data,
* jffs2_compress should compress as much as will fit, and should set
* *datalen accordingly to show the amount of data which were compressed.
*/
uint16_t jffs2_compress( unsigned char *data_in, unsigned char **cpage_out,
uint32_t *datalen, uint32_t *cdatalen)
{
int ret = JFFS2_COMPR_NONE;
int compr_ret;
struct jffs2_compressor *this_, *best=NULL;
unsigned char *output_buf = NULL, *tmp_buf;
uint32_t orig_slen, orig_dlen;
uint32_t best_slen=0, best_dlen=0;
switch (jffs2_compression_mode) {
case JFFS2_COMPR_MODE_NONE:
break;
case JFFS2_COMPR_MODE_PRIORITY:
orig_slen = *datalen;
orig_dlen = *cdatalen;
output_buf = (unsigned char*)malloc(orig_dlen+jffs2_compression_check);
if (!output_buf) {
fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. Compression failed.\n");
goto out;
}
list_for_each_entry(this_, &jffs2_compressor_list, list) {
/* Skip decompress-only backwards-compatibility and disabled modules */
if ((!this_->compress)||(this_->disabled))
continue;
this_->usecount++;
if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
jffs2_decompression_test_prepare(output_buf, orig_dlen);
*datalen = orig_slen;
*cdatalen = orig_dlen;
compr_ret = this_->compress(data_in, output_buf, datalen, cdatalen);
this_->usecount--;
if (!compr_ret) {
ret = this_->compr;
this_->stat_compr_blocks++;
this_->stat_compr_orig_size += *datalen;
this_->stat_compr_new_size += *cdatalen;
if (jffs2_compression_check)
jffs2_decompression_test(this_, data_in, output_buf, *cdatalen, *datalen, orig_dlen);
break;
}
}
if (ret == JFFS2_COMPR_NONE) free(output_buf);
break;
case JFFS2_COMPR_MODE_FAVOURLZO:
case JFFS2_COMPR_MODE_SIZE:
orig_slen = *datalen;
orig_dlen = *cdatalen;
list_for_each_entry(this_, &jffs2_compressor_list, list) {
uint32_t needed_buf_size;
if (jffs2_compression_mode == JFFS2_COMPR_MODE_FAVOURLZO)
needed_buf_size = orig_slen + jffs2_compression_check;
else
needed_buf_size = orig_dlen + jffs2_compression_check;
/* Skip decompress-only backwards-compatibility and disabled modules */
if ((!this_->compress)||(this_->disabled))
continue;
/* Allocating memory for output buffer if necessary */
if ((this_->compr_buf_size < needed_buf_size) && (this_->compr_buf)) {
free(this_->compr_buf);
this_->compr_buf_size=0;
this_->compr_buf=NULL;
}
if (!this_->compr_buf) {
tmp_buf = (unsigned char*)malloc(needed_buf_size);
if (!tmp_buf) {
fprintf(stderr,"mkfs.jffs2: No memory for compressor allocation. (%d bytes)\n",orig_dlen);
continue;
}
else {
this_->compr_buf = tmp_buf;
this_->compr_buf_size = orig_dlen;
}
}
this_->usecount++;
if (jffs2_compression_check) /*preparing output buffer for testing buffer overflow */
jffs2_decompression_test_prepare(this_->compr_buf,this_->compr_buf_size);
*datalen = orig_slen;
*cdatalen = orig_dlen;
compr_ret = this_->compress(data_in, this_->compr_buf, datalen, cdatalen);
this_->usecount--;
if (!compr_ret) {
if (jffs2_compression_check)
jffs2_decompression_test(this_, data_in, this_->compr_buf, *cdatalen, *datalen, this_->compr_buf_size);
if (((!best_dlen) || jffs2_is_best_compression(this_, best, *cdatalen, best_dlen))
&& (*cdatalen < *datalen)) {
best_dlen = *cdatalen;
best_slen = *datalen;
best = this_;
}
}
}
if (best_dlen) {
*cdatalen = best_dlen;
*datalen = best_slen;
output_buf = best->compr_buf;
best->compr_buf = NULL;
best->compr_buf_size = 0;
best->stat_compr_blocks++;
best->stat_compr_orig_size += best_slen;
best->stat_compr_new_size += best_dlen;
ret = best->compr;
}
break;
default:
fprintf(stderr,"mkfs.jffs2: unknown compression mode.\n");
}
out:
if (ret == JFFS2_COMPR_NONE) {
*cpage_out = data_in;
*datalen = *cdatalen;
none_stat_compr_blocks++;
none_stat_compr_size += *datalen;
}
else {
*cpage_out = output_buf;
}
return ret;
}
int jffs2_register_compressor(struct jffs2_compressor *comp)
{
struct jffs2_compressor *this_;
if (!comp->name) {
fprintf(stderr,"NULL compressor name at registering JFFS2 compressor. Failed.\n");
return -1;
}
comp->compr_buf_size=0;
comp->compr_buf=NULL;
comp->usecount=0;
comp->stat_compr_orig_size=0;
comp->stat_compr_new_size=0;
comp->stat_compr_blocks=0;
comp->stat_decompr_blocks=0;
list_for_each_entry(this_, &jffs2_compressor_list, list) {
if (this_->priority < comp->priority) {
list_add(&comp->list, this_->list.prev);
goto out;
}
}
list_add_tail(&comp->list, &jffs2_compressor_list);
out:
return 0;
}
int jffs2_unregister_compressor(struct jffs2_compressor *comp)
{
if (comp->usecount) {
fprintf(stderr,"mkfs.jffs2: Compressor modul is in use. Unregister failed.\n");
return -1;
}
list_del(&comp->list);
return 0;
}
#define JFFS2_STAT_BUF_SIZE 16000
char *jffs2_list_compressors(void)
{
struct jffs2_compressor *this_;
char *buf, *act_buf;
act_buf = buf = (char*)malloc(JFFS2_STAT_BUF_SIZE);
list_for_each_entry(this_, &jffs2_compressor_list, list) {
act_buf += sprintf(act_buf, "%10s priority:%d ", this_->name, this_->priority);
if ((this_->disabled)||(!this_->compress))
act_buf += sprintf(act_buf,"disabled");
else
act_buf += sprintf(act_buf,"enabled");
act_buf += sprintf(act_buf,"\n");
}
return buf;
}
char *jffs2_stats(void)
{
struct jffs2_compressor *this_;
char *buf, *act_buf;
act_buf = buf = (char*)malloc(JFFS2_STAT_BUF_SIZE);
act_buf += sprintf(act_buf,"Compression mode: ");
switch (jffs2_compression_mode) {
case JFFS2_COMPR_MODE_NONE:
act_buf += sprintf(act_buf,"none");
break;
case JFFS2_COMPR_MODE_PRIORITY:
act_buf += sprintf(act_buf,"priority");
break;
case JFFS2_COMPR_MODE_SIZE:
act_buf += sprintf(act_buf,"size");
break;
case JFFS2_COMPR_MODE_FAVOURLZO:
act_buf += sprintf(act_buf, "favourlzo");
break;
default:
act_buf += sprintf(act_buf, "unknown");
break;
}
act_buf += sprintf(act_buf,"\nCompressors:\n");
act_buf += sprintf(act_buf,"%10s ","none");
act_buf += sprintf(act_buf,"compr: %d blocks (%d) decompr: %d blocks\n", none_stat_compr_blocks,
none_stat_compr_size, none_stat_decompr_blocks);
list_for_each_entry(this_, &jffs2_compressor_list, list) {
act_buf += sprintf(act_buf,"%10s (prio:%d) ",this_->name,this_->priority);
if ((this_->disabled)||(!this_->compress))
act_buf += sprintf(act_buf,"- ");
else
act_buf += sprintf(act_buf,"+ ");
act_buf += sprintf(act_buf,"compr: %d blocks (%d/%d) decompr: %d blocks ", this_->stat_compr_blocks,
this_->stat_compr_new_size, this_->stat_compr_orig_size,
this_->stat_decompr_blocks);
act_buf += sprintf(act_buf,"\n");
}
return buf;
}
int jffs2_set_compression_mode_name(const char *name)
{
if (!strcmp("none",name)) {
jffs2_compression_mode = JFFS2_COMPR_MODE_NONE;
return 0;
}
if (!strcmp("priority",name)) {
jffs2_compression_mode = JFFS2_COMPR_MODE_PRIORITY;
return 0;
}
if (!strcmp("size",name)) {
jffs2_compression_mode = JFFS2_COMPR_MODE_SIZE;
return 0;
}
if (!strcmp("favourlzo", name)) {
jffs2_compression_mode = JFFS2_COMPR_MODE_FAVOURLZO;
return 0;
}
return 1;
}
static int jffs2_compressor_Xable(const char *name, int disabled)
{
struct jffs2_compressor *this_;
list_for_each_entry(this_, &jffs2_compressor_list, list) {
if (!strcmp(this_->name, name)) {
this_->disabled = disabled;
return 0;
}
}
return 1;
}
int jffs2_enable_compressor_name(const char *name)
{
return jffs2_compressor_Xable(name, 0);
}
int jffs2_disable_compressor_name(const char *name)
{
return jffs2_compressor_Xable(name, 1);
}
int jffs2_set_compressor_priority(const char *name, int priority)
{
struct jffs2_compressor *this_,*comp;
list_for_each_entry(this_, &jffs2_compressor_list, list) {
if (!strcmp(this_->name, name)) {
this_->priority = priority;
comp = this_;
goto reinsert;
}
}
fprintf(stderr,"mkfs.jffs2: compressor %s not found.\n",name);
return 1;
reinsert:
/* list is sorted in the order of priority, so if
we change it we have to reinsert it into the
good place */
list_del(&comp->list);
list_for_each_entry(this_, &jffs2_compressor_list, list) {
if (this_->priority < comp->priority) {
list_add(&comp->list, this_->list.prev);
return 0;
}
}
list_add_tail(&comp->list, &jffs2_compressor_list);
return 0;
}
int jffs2_compressors_init(void)
{
#ifdef CONFIG_JFFS2_ZLIB
jffs2_zlib_init();
#endif
#ifdef CONFIG_JFFS2_RTIME
jffs2_rtime_init();
#endif
#ifdef CONFIG_JFFS2_LZO
jffs2_lzo_init();
#endif
return 0;
}
int jffs2_compressors_exit(void)
{
#ifdef CONFIG_JFFS2_RTIME
jffs2_rtime_exit();
#endif
#ifdef CONFIG_JFFS2_ZLIB
jffs2_zlib_exit();
#endif
#ifdef CONFIG_JFFS2_LZO
jffs2_lzo_exit();
#endif
return 0;
}

119
src/system/mtdutils/compr.h Normal file
View File

@@ -0,0 +1,119 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*/
#ifndef __JFFS2_COMPR_H__
#define __JFFS2_COMPR_H__
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "linux/jffs2.h"
#define CONFIG_JFFS2_ZLIB
#define CONFIG_JFFS2_RTIME
#define CONFIG_JFFS2_LZO
#define JFFS2_RUBINMIPS_PRIORITY 10
#define JFFS2_DYNRUBIN_PRIORITY 20
#define JFFS2_RTIME_PRIORITY 50
#define JFFS2_ZLIB_PRIORITY 60
#define JFFS2_LZO_PRIORITY 80
#define JFFS2_COMPR_MODE_NONE 0
#define JFFS2_COMPR_MODE_PRIORITY 1
#define JFFS2_COMPR_MODE_SIZE 2
#define JFFS2_COMPR_MODE_FAVOURLZO 3
#define kmalloc(a,b) malloc(a)
#define kfree(a) free(a)
#ifndef GFP_KERNEL
#define GFP_KERNEL 0
#endif
#define vmalloc(a) malloc(a)
#define vfree(a) free(a)
#define printk(...) fprintf(stderr,__VA_ARGS__)
#define KERN_EMERG
#define KERN_ALERT
#define KERN_CRIT
#define KERN_ERR
#define KERN_WARNING
#define KERN_NOTICE
#define KERN_INFO
#define KERN_DEBUG
struct list_head {
struct list_head *next, *prev;
};
void jffs2_set_compression_mode(int mode);
int jffs2_get_compression_mode(void);
int jffs2_set_compression_mode_name(const char *mode_name);
int jffs2_enable_compressor_name(const char *name);
int jffs2_disable_compressor_name(const char *name);
int jffs2_set_compressor_priority(const char *name, int priority);
struct jffs2_compressor {
struct list_head list;
int priority; /* used by prirority comr. mode */
const char *name;
char compr; /* JFFS2_COMPR_XXX */
int (*compress)(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *srclen, uint32_t *destlen);
int (*decompress)(unsigned char *cdata_in, unsigned char *data_out,
uint32_t cdatalen, uint32_t datalen);
int usecount;
int disabled; /* if seted the compressor won't compress */
unsigned char *compr_buf; /* used by size compr. mode */
uint32_t compr_buf_size; /* used by size compr. mode */
uint32_t stat_compr_orig_size;
uint32_t stat_compr_new_size;
uint32_t stat_compr_blocks;
uint32_t stat_decompr_blocks;
};
int jffs2_register_compressor(struct jffs2_compressor *comp);
int jffs2_unregister_compressor(struct jffs2_compressor *comp);
int jffs2_compressors_init(void);
int jffs2_compressors_exit(void);
uint16_t jffs2_compress(unsigned char *data_in, unsigned char **cpage_out,
uint32_t *datalen, uint32_t *cdatalen);
/* If it is setted, a decompress will be called after every compress */
void jffs2_compression_check_set(int yesno);
int jffs2_compression_check_get(void);
int jffs2_compression_check_errorcnt_get(void);
char *jffs2_list_compressors(void);
char *jffs2_stats(void);
/* Compressor modules */
/* These functions will be called by jffs2_compressors_init/exit */
#ifdef CONFIG_JFFS2_ZLIB
int jffs2_zlib_init(void);
void jffs2_zlib_exit(void);
#endif
#ifdef CONFIG_JFFS2_RTIME
int jffs2_rtime_init(void);
void jffs2_rtime_exit(void);
#endif
#ifdef CONFIG_JFFS2_LZO
int jffs2_lzo_init(void);
void jffs2_lzo_exit(void);
#endif
#endif /* __JFFS2_COMPR_H__ */

View File

@@ -0,0 +1,137 @@
/*
* JFFS2 LZO Compression Interface.
*
* Copyright (C) 2007 Nokia Corporation. All rights reserved.
*
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
*/
#define WITHOUT_LZO
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifndef WITHOUT_LZO
#include <asm/types.h>
#include <linux/jffs2.h>
#include <lzo/lzo1x.h>
#include "compr.h"
extern int page_size;
static void *lzo_mem;
static void *lzo_compress_buf;
/*
* Note about LZO compression.
*
* We want to use the _999_ compression routine which gives better compression
* rates at the expense of time. Decompression time is unaffected. We might as
* well use the standard lzo library routines for this but they will overflow
* the destination buffer since they don't check the destination size.
*
* We therefore compress to a temporary buffer and copy if it will fit.
*
*/
static int jffs2_lzo_cmpr(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
lzo_uint compress_size;
int ret;
ret = lzo1x_999_compress(data_in, *sourcelen, lzo_compress_buf, &compress_size, lzo_mem);
if (ret != LZO_E_OK)
return -1;
if (compress_size > *dstlen)
return -1;
memcpy(cpage_out, lzo_compress_buf, compress_size);
*dstlen = compress_size;
return 0;
}
static int jffs2_lzo_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t srclen, uint32_t destlen)
{
int ret;
lzo_uint dl;
ret = lzo1x_decompress_safe(data_in,srclen,cpage_out,&dl,NULL);
if (ret != LZO_E_OK || dl != destlen)
return -1;
return 0;
}
static struct jffs2_compressor jffs2_lzo_comp = {
.priority = JFFS2_LZO_PRIORITY,
.name = "lzo",
.compr = JFFS2_COMPR_LZO,
.compress = &jffs2_lzo_cmpr,
.decompress = &jffs2_lzo_decompress,
.disabled = 1,
};
int jffs2_lzo_init(void)
{
int ret;
lzo_mem = malloc(LZO1X_999_MEM_COMPRESS);
if (!lzo_mem)
return -1;
/* Worse case LZO compression size from their FAQ */
lzo_compress_buf = malloc(page_size + (page_size / 16) + 64 + 3);
if (!lzo_compress_buf) {
free(lzo_mem);
return -1;
}
ret = jffs2_register_compressor(&jffs2_lzo_comp);
if (ret < 0) {
free(lzo_compress_buf);
free(lzo_mem);
}
return ret;
}
void jffs2_lzo_exit(void)
{
jffs2_unregister_compressor(&jffs2_lzo_comp);
free(lzo_compress_buf);
free(lzo_mem);
}
#else
int jffs2_lzo_init(void)
{
return 0;
}
void jffs2_lzo_exit(void)
{
}
#endif

View File

@@ -0,0 +1,124 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by Arjan van de Ven <arjanv@redhat.com>
*
* For licensing information, see the file 'LICENCE' in this directory.
*
* Very simple lz77-ish encoder.
*
* Theory of operation: Both encoder and decoder have a list of "last
* occurrences" 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 <stdint.h>
#include <string.h>
#include "compr.h"
/* _compress returns the compressed size, -1 if bigger */
static int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
short positions[256];
int outpos = 0;
int pos=0;
memset(positions,0,sizeof(positions));
while (pos < (*sourcelen) && outpos+2 <= (*dstlen)) {
int backpos, runlen=0;
unsigned char value;
value = data_in[pos];
cpage_out[outpos++] = data_in[pos++];
backpos = positions[value];
positions[value]=pos;
while ((backpos < pos) && (pos < (*sourcelen)) &&
(data_in[pos]==data_in[backpos++]) && (runlen<255)) {
pos++;
runlen++;
}
cpage_out[outpos++] = runlen;
}
if (outpos >= pos) {
/* We failed */
return -1;
}
/* Tell the caller how much we managed to compress, and how much space it took */
*sourcelen = pos;
*dstlen = outpos;
return 0;
}
static int jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out,
__attribute__((unused)) uint32_t srclen, uint32_t destlen)
{
short positions[256];
uint32_t outpos = 0;
int pos=0;
memset(positions,0,sizeof(positions));
while (outpos<destlen) {
unsigned char value;
uint32_t backoffs;
uint32_t 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 {
memcpy(&cpage_out[outpos],&cpage_out[backoffs],repeat);
outpos+=repeat;
}
}
}
return 0;
}
static struct jffs2_compressor jffs2_rtime_comp;
void fill_jffs2_rtime_compressor_struct();
void fill_jffs2_rtime_compressor_struct()
{
jffs2_rtime_comp.priority = JFFS2_RTIME_PRIORITY;
jffs2_rtime_comp.name = "rtime";
jffs2_rtime_comp.disabled = 0;
jffs2_rtime_comp.compr = JFFS2_COMPR_RTIME;
jffs2_rtime_comp.compress = &jffs2_rtime_compress;
jffs2_rtime_comp.decompress = &jffs2_rtime_decompress;
}
int jffs2_rtime_init(void)
{
fill_jffs2_rtime_compressor_struct();
return jffs2_register_compressor(&jffs2_rtime_comp);
}
void jffs2_rtime_exit(void)
{
fill_jffs2_rtime_compressor_struct();
jffs2_unregister_compressor(&jffs2_rtime_comp);
}

View File

@@ -0,0 +1,154 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@cambridge.redhat.com>
*
* 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.
*/
#define PROGRAM_NAME "compr_zlib"
#include <stdint.h>
#define crc32 __zlib_crc32
#include <zlib.h>
#undef crc32
#include <stdio.h>
#include <asm/types.h>
#include <linux/jffs2.h>
#include "common.h"
#include "compr.h"
/* Plan: call deflate() with avail_in == *sourcelen,
avail_out = *dstlen - 12 and flush == Z_FINISH.
If it doesn't manage to finish, call it again with
avail_in == 0 and avail_out set to the remaining 12
bytes for it to clean up.
Q: Is 12 bytes sufficient?
*/
#define STREAM_END_SPACE 12
static int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t *sourcelen, uint32_t *dstlen)
{
z_stream strm;
int ret;
if (*dstlen <= STREAM_END_SPACE)
return -1;
strm.zalloc = NULL;
strm.zfree = NULL;
if (Z_OK != deflateInit(&strm, 3)) {
return -1;
}
strm.next_in = data_in;
strm.total_in = 0;
strm.next_out = cpage_out;
strm.total_out = 0;
while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) {
strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE);
strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out);
ret = deflate(&strm, Z_PARTIAL_FLUSH);
if (ret != Z_OK) {
deflateEnd(&strm);
return -1;
}
}
strm.avail_out += STREAM_END_SPACE;
strm.avail_in = 0;
ret = deflate(&strm, Z_FINISH);
if (ret != Z_STREAM_END) {
deflateEnd(&strm);
return -1;
}
deflateEnd(&strm);
if (strm.total_out >= strm.total_in)
return -1;
*dstlen = strm.total_out;
*sourcelen = strm.total_in;
return 0;
}
static int jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out,
uint32_t srclen, uint32_t destlen)
{
z_stream strm;
int ret;
strm.zalloc = NULL;
strm.zfree = NULL;
if (Z_OK != inflateInit(&strm)) {
return 1;
}
strm.next_in = data_in;
strm.avail_in = srclen;
strm.total_in = 0;
strm.next_out = cpage_out;
strm.avail_out = destlen;
strm.total_out = 0;
while((ret = inflate(&strm, Z_FINISH)) == Z_OK)
;
inflateEnd(&strm);
return 0;
}
static struct jffs2_compressor jffs2_zlib_comp;
void fill_jffs2_zlib_compressor_struct();
void fill_jffs2_zlib_compressor_struct()
{
jffs2_zlib_comp.priority = JFFS2_ZLIB_PRIORITY;
jffs2_zlib_comp.name = "zlib";
jffs2_zlib_comp.disabled = 0;
jffs2_zlib_comp.compr = JFFS2_COMPR_ZLIB;
jffs2_zlib_comp.compress = &jffs2_zlib_compress;
jffs2_zlib_comp.decompress = &jffs2_zlib_decompress;
}
int jffs2_zlib_init(void)
{
fill_jffs2_zlib_compressor_struct();
return jffs2_register_compressor(&jffs2_zlib_comp);
}
void jffs2_zlib_exit(void)
{
fill_jffs2_zlib_compressor_struct();
jffs2_unregister_compressor(&jffs2_zlib_comp);
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) Artem Bityutskiy, 2007, 2008
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MTD_UTILS_COMMON_H__
#define __MTD_UTILS_COMMON_H__
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <features.h>
#include <inttypes.h>
#ifndef PROGRAM_NAME
# error "You must define PROGRAM_NAME before including this header"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#ifndef MIN /* some C lib headers define this for us */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
#ifndef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
#define min(a, b) MIN(a, b) /* glue for linux kernel source */
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
/* define a print format specifier for off_t */
#ifdef __USE_FILE_OFFSET64
#define PRIxoff_t PRIx64
#define PRIdoff_t PRId64
#else
#define PRIxoff_t "l"PRIx32
#define PRIdoff_t "l"PRId32
#endif
/* Verbose messages */
#define bareverbose(verbose, fmt, ...) do { \
if (verbose) \
printf(fmt, ##__VA_ARGS__); \
} while(0)
#define verbose(verbose, fmt, ...) \
bareverbose(verbose, "%s: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__)
/* Normal messages */
#define normsg_cont(fmt, ...) do { \
printf("%s: " fmt, PROGRAM_NAME, ##__VA_ARGS__); \
} while(0)
#define normsg(fmt, ...) do { \
normsg_cont(fmt "\n", ##__VA_ARGS__); \
} while(0)
/* Error messages */
#define errmsg(fmt, ...) ({ \
fprintf(stderr, "%s: error!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
-1; \
})
/* System error messages */
#define sys_errmsg(fmt, ...) ({ \
int _err = errno; \
errmsg(fmt, ##__VA_ARGS__); \
fprintf(stderr, "%*serror %d (%s)\n", (int)sizeof(PROGRAM_NAME) + 1,\
"", _err, strerror(_err)); \
-1; \
})
/* Warnings */
#define warnmsg(fmt, ...) do { \
fprintf(stderr, "%s: warning!: " fmt "\n", PROGRAM_NAME, ##__VA_ARGS__); \
} while(0)
static inline int is_power_of_2(unsigned long long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
/**
* simple_strtoX - convert a hex/dec/oct string into a number
* @snum: buffer to convert
* @error: set to 1 when buffer isn't fully consumed
*
* These functions are similar to the standard strtoX() functions, but they are
* a little bit easier to use if you want to convert full string of digits into
* the binary form. The typical usage:
*
* int error = 0;
* unsigned long num;
*
* num = simple_strtoul(str, &error);
* if (error || ... if needed, your check that num is not out of range ...)
* error_happened();
*/
#define simple_strtoX(func, type) \
static inline type simple_##func(const char *snum, int *error) \
{ \
char *endptr; \
type ret = func(snum, &endptr, 0); \
\
if (error && (!*snum || *endptr)) { \
errmsg("%s: unable to parse the number '%s'", #func, snum); \
*error = 1; \
} \
\
return ret; \
}
simple_strtoX(strtol, long int)
simple_strtoX(strtoll, long long int)
simple_strtoX(strtoul, unsigned long int)
simple_strtoX(strtoull, unsigned long long int)
/* Simple version-printing for utils */
#define common_print_version() \
do { \
printf("%s %s\n", PROGRAM_NAME, X_VERSION); \
} while (0)
#include "xalloc.h"
#ifdef __cplusplus
}
#endif
#endif /* !__MTD_UTILS_COMMON_H__ */

View File

@@ -0,0 +1,13 @@
/*
* This code was taken from the linux kernel. The license is GPL Version 2.
*/
#ifndef __CRC32_H__
#define __CRC32_H__
#include <stdint.h>
/* Return a 32-bit CRC of the contents of the buffer */
extern uint32_t mtd_crc32(uint32_t val, const void *ss, int len);
#endif /* __CRC32_H__ */

View File

@@ -0,0 +1,352 @@
/*
* Copyright (C) 2008, 2009 Nokia Corporation
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author: Artem Bityutskiy
*
* MTD library.
*/
#ifndef __LIBMTD_H__
#define __LIBMTD_H__
#ifdef __cplusplus
extern "C" {
#endif
/* Maximum MTD device name length */
#define MTD_NAME_MAX 127
/* Maximum MTD device type string length */
#define MTD_TYPE_MAX 64
/* MTD library descriptor */
typedef void * libmtd_t;
/* Forward decls */
struct region_info_user;
/**
* @mtd_dev_cnt: count of MTD devices in system
* @lowest_mtd_num: lowest MTD device number in system
* @highest_mtd_num: highest MTD device number in system
* @sysfs_supported: non-zero if sysfs is supported by MTD
*/
struct mtd_info
{
int mtd_dev_cnt;
int lowest_mtd_num;
int highest_mtd_num;
unsigned int sysfs_supported:1;
};
/**
* struct mtd_dev_info - information about an MTD device.
* @mtd_num: MTD device number
* @major: major number of corresponding character device
* @minor: minor number of corresponding character device
* @type: flash type (constants like %MTD_NANDFLASH defined in mtd-abi.h)
* @type_str: static R/O flash type string
* @name: device name
* @size: device size in bytes
* @eb_cnt: count of eraseblocks
* @eb_size: eraseblock size
* @min_io_size: minimum input/output unit size
* @subpage_size: sub-page size
* @oob_size: OOB size (zero if the device does not have OOB area)
* @region_cnt: count of additional erase regions
* @writable: zero if the device is read-only
* @bb_allowed: non-zero if the MTD device may have bad eraseblocks
*/
struct mtd_dev_info
{
int mtd_num;
int major;
int minor;
int type;
const char type_str[MTD_TYPE_MAX + 1];
const char name[MTD_NAME_MAX + 1];
long long size;
int eb_cnt;
int eb_size;
int min_io_size;
int subpage_size;
int oob_size;
int region_cnt;
unsigned int writable:1;
unsigned int bb_allowed:1;
};
/**
* libmtd_open - open MTD library.
*
* This function initializes and opens the MTD library and returns MTD library
* descriptor in case of success and %NULL in case of failure. In case of
* failure, errno contains zero if MTD is not present in the system, or
* contains the error code if a real error happened.
*/
libmtd_t libmtd_open(void);
/**
* libmtd_close - close MTD library.
* @desc: MTD library descriptor
*/
void libmtd_close(libmtd_t desc);
/**
* mtd_dev_present - check whether a MTD device is present.
* @desc: MTD library descriptor
* @mtd_num: MTD device number to check
*
* This function returns %1 if MTD device is present and %0 if not.
*/
int mtd_dev_present(libmtd_t desc, int mtd_num);
/**
* mtd_get_info - get general MTD information.
* @desc: MTD library descriptor
* @info: the MTD device information is returned here
*
* This function fills the passed @info object with general MTD information and
* returns %0 in case of success and %-1 in case of failure. If MTD subsystem is
* not present in the system, errno is set to @ENODEV.
*/
int mtd_get_info(libmtd_t desc, struct mtd_info *info);
/**
* mtd_get_dev_info - get information about an MTD device.
* @desc: MTD library descriptor
* @node: name of the MTD device node
* @mtd: the MTD device information is returned here
*
* This function gets information about MTD device defined by the @node device
* node file and saves this information in the @mtd object. Returns %0 in case
* of success and %-1 in case of failure. If MTD subsystem is not present in the
* system, or the MTD device does not exist, errno is set to @ENODEV.
*/
int mtd_get_dev_info(libmtd_t desc, const char *node, struct mtd_dev_info *mtd);
/**
* mtd_get_dev_info1 - get information about an MTD device.
* @desc: MTD library descriptor
* @mtd_num: MTD device number to fetch information about
* @mtd: the MTD device information is returned here
*
* This function is identical to 'mtd_get_dev_info()' except that it accepts
* MTD device number, not MTD character device.
*/
int mtd_get_dev_info1(libmtd_t desc, int mtd_num, struct mtd_dev_info *mtd);
/**
* mtd_lock - lock eraseblocks.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to lock
*
* This function locks eraseblock @eb. Returns %0 in case of success and %-1
* in case of failure.
*/
int mtd_lock(const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_unlock - unlock eraseblocks.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to lock
*
* This function unlocks eraseblock @eb. Returns %0 in case of success and %-1
* in case of failure.
*/
int mtd_unlock(const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_erase - erase an eraseblock.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to erase
*
* This function erases eraseblock @eb of MTD device described by @fd. Returns
* %0 in case of success and %-1 in case of failure.
*/
int mtd_erase(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_regioninfo - get information about an erase region.
* @fd: MTD device node file descriptor
* @regidx: index of region to look up
* @reginfo: the region information is returned here
*
* This function gets information about an erase region defined by the
* @regidx index and saves this information in the @reginfo object.
* Returns %0 in case of success and %-1 in case of failure. If the
* @regidx is not valid or unavailable, errno is set to @ENODEV.
*/
int mtd_regioninfo(int fd, int regidx, struct region_info_user *reginfo);
/**
* mtd_is_locked - see if the specified eraseblock is locked.
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to check
*
* This function checks to see if eraseblock @eb of MTD device described
* by @fd is locked. Returns %0 if it is unlocked, %1 if it is locked, and
* %-1 in case of failure. If the ioctl is not supported (support was added in
* Linux kernel 2.6.36) or this particular device does not support it, errno is
* set to @ENOTSUPP.
*/
int mtd_is_locked(const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_torture - torture an eraseblock.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to torture
*
* This function tortures eraseblock @eb. Returns %0 in case of success and %-1
* in case of failure.
*/
int mtd_torture(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_is_bad - check if eraseblock is bad.
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to check
*
* This function checks if eraseblock @eb is bad. Returns %0 if not, %1 if yes,
* and %-1 in case of failure.
*/
int mtd_is_bad(const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_mark_bad - mark an eraseblock as bad.
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to mark as bad
*
* This function marks eraseblock @eb as bad. Returns %0 in case of success and
* %-1 in case of failure.
*/
int mtd_mark_bad(const struct mtd_dev_info *mtd, int fd, int eb);
/**
* mtd_read - read data from an MTD device.
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to read from
* @offs: offset withing the eraseblock to read from
* @buf: buffer to read data to
* @len: how many bytes to read
*
* This function reads @len bytes of data from eraseblock @eb and offset @offs
* of the MTD device defined by @mtd and stores the read data at buffer @buf.
* Returns %0 in case of success and %-1 in case of failure.
*/
int mtd_read(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
void *buf, int len);
/**
* mtd_write - write data to an MTD device.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to write to
* @offs: offset withing the eraseblock to write to
* @data: data buffer to write
* @len: how many data bytes to write
* @oob: OOB buffer to write
* @ooblen: how many OOB bytes to write
* @mode: write mode (e.g., %MTD_OOB_PLACE, %MTD_OOB_RAW)
*
* This function writes @len bytes of data to eraseblock @eb and offset @offs
* of the MTD device defined by @mtd. Returns %0 in case of success and %-1 in
* case of failure.
*
* Can only write to a single page at a time if writing to OOB.
*/
int mtd_write(libmtd_t desc, const struct mtd_dev_info *mtd, int fd, int eb,
int offs, void *data, int len, void *oob, int ooblen,
uint8_t mode);
/**
* mtd_read_oob - read out-of-band area.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @start: page-aligned start address
* @length: number of OOB bytes to read
* @data: read buffer
*
* This function reads @length OOB bytes starting from address @start on
* MTD device described by @fd. The address is specified as page byte offset
* from the beginning of the MTD device. This function returns %0 in case of
* success and %-1 in case of failure.
*/
int mtd_read_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
uint64_t start, uint64_t length, void *data);
/**
* mtd_write_oob - write out-of-band area.
* @desc: MTD library descriptor
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @start: page-aligned start address
* @length: number of OOB bytes to write
* @data: write buffer
*
* This function writes @length OOB bytes starting from address @start on
* MTD device described by @fd. The address is specified as page byte offset
* from the beginning of the MTD device. Returns %0 in case of success and %-1
* in case of failure.
*/
int mtd_write_oob(libmtd_t desc, const struct mtd_dev_info *mtd, int fd,
uint64_t start, uint64_t length, void *data);
/**
* mtd_write_img - write a file to MTD device.
* @mtd: MTD device description object
* @fd: MTD device node file descriptor
* @eb: eraseblock to write to
* @offs: offset withing the eraseblock to write to
* @img_name: the file to write
*
* This function writes an image @img_name the MTD device defined by @mtd. @eb
* and @offs are the starting eraseblock and offset on the MTD device. Returns
* %0 in case of success and %-1 in case of failure.
*/
int mtd_write_img(const struct mtd_dev_info *mtd, int fd, int eb, int offs,
const char *img_name);
/**
* mtd_probe_node - test MTD node.
* @desc: MTD library descriptor
* @node: the node to test
*
* This function tests whether @node is an MTD device node and returns %1 if it
* is, and %-1 if it is not (errno is %ENODEV in this case) or if an error
* occurred.
*/
int mtd_probe_node(libmtd_t desc, const char *node);
#ifdef __cplusplus
}
#endif
#endif /* __LIBMTD_H__ */

View File

@@ -0,0 +1,218 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2001-2003 Red Hat, Inc.
*
* Created by David Woodhouse <dwmw2@infradead.org>
*
* For licensing information, see the file 'LICENCE' in the
* jffs2 directory.
*
* $Id: jffs2.h,v 1.38 2005/09/26 11:37:23 havasi Exp $
*
*/
#ifndef __LINUX_JFFS2_H__
#define __LINUX_JFFS2_H__
/* You must include something which defines the C99 uintXX_t types.
We don't do it from here because this file is used in too many
different environments. */
#define JFFS2_SUPER_MAGIC 0x72b6
/* Values we may expect to find in the 'magic' field */
#define JFFS2_OLD_MAGIC_BITMASK 0x1984
#define JFFS2_MAGIC_BITMASK 0x1985
#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */
#define JFFS2_EMPTY_BITMASK 0xffff
#define JFFS2_DIRTY_BITMASK 0x0000
/* Summary node MAGIC marker */
#define JFFS2_SUM_MAGIC 0x02851885
/* We only allow a single char for length, and 0xFF is empty flash so
we don't want it confused with a real length. Hence max 254.
*/
#define JFFS2_MAX_NAME_LEN 254
/* How small can we sensibly write nodes? */
#define JFFS2_MIN_DATA_LEN 128
#define JFFS2_COMPR_NONE 0x00
#define JFFS2_COMPR_ZERO 0x01
#define JFFS2_COMPR_RTIME 0x02
#define JFFS2_COMPR_RUBINMIPS 0x03
#define JFFS2_COMPR_COPY 0x04
#define JFFS2_COMPR_DYNRUBIN 0x05
#define JFFS2_COMPR_ZLIB 0x06
#define JFFS2_COMPR_LZO 0x07
/* Compatibility flags. */
#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */
#define JFFS2_NODE_ACCURATE 0x2000
/* INCOMPAT: Fail to mount the filesystem */
#define JFFS2_FEATURE_INCOMPAT 0xc000
/* ROCOMPAT: Mount read-only */
#define JFFS2_FEATURE_ROCOMPAT 0x8000
/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000
/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */
#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000
#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1)
#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2)
#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6)
#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8)
#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9)
/* XATTR Related */
#define JFFS2_XPREFIX_USER 1 /* for "user." */
#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */
#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */
#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */
#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */
#define JFFS2_ACL_VERSION 0x0001
// Maybe later...
//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3)
//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4)
#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at
mount time, don't wait for it to
happen later */
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
compression type */
/* These can go once we've made sure we've caught all uses without
byteswapping */
typedef struct {
uint32_t v32;
} __attribute__((packed)) jint32_t;
typedef struct {
uint32_t m;
} __attribute__((packed)) jmode_t;
typedef struct {
uint16_t v16;
} __attribute__((packed)) jint16_t;
struct jffs2_unknown_node
{
/* All start like this */
jint16_t magic;
jint16_t nodetype;
jint32_t totlen; /* So we can skip over nodes we don't grok */
jint32_t hdr_crc;
} __attribute__((packed));
struct jffs2_raw_dirent
{
jint16_t magic;
jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t pino;
jint32_t version;
jint32_t ino; /* == zero for unlink */
jint32_t mctime;
uint8_t nsize;
uint8_t type;
uint8_t unused[2];
jint32_t node_crc;
jint32_t name_crc;
uint8_t name[0];
} __attribute__((packed));
/* The JFFS2 raw inode structure: Used for storage on physical media. */
/* The uid, gid, atime, mtime and ctime members could be longer, but
are left like this for space efficiency. If and when people decide
they really need them extended, it's simple enough to add support for
a new type of raw node.
*/
struct jffs2_raw_inode
{
jint16_t magic; /* A constant magic number. */
jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */
jint32_t totlen; /* Total length of this node (inc data, etc.) */
jint32_t hdr_crc;
jint32_t ino; /* Inode number. */
jint32_t version; /* Version number. */
jmode_t mode; /* The file's type or mode. */
jint16_t uid; /* The file's owner. */
jint16_t gid; /* The file's group. */
jint32_t isize; /* Total resultant size of this inode (used for truncations) */
jint32_t atime; /* Last access time. */
jint32_t mtime; /* Last modification time. */
jint32_t ctime; /* Change time. */
jint32_t offset; /* Where to begin to write. */
jint32_t csize; /* (Compressed) data size */
jint32_t dsize; /* Size of the node's data. (after decompression) */
uint8_t compr; /* Compression algorithm used */
uint8_t usercompr; /* Compression algorithm requested by the user */
jint16_t flags; /* See JFFS2_INO_FLAG_* */
jint32_t data_crc; /* CRC for the (compressed) data. */
jint32_t node_crc; /* CRC for the raw inode (excluding data) */
uint8_t data[0];
} __attribute__((packed));
struct jffs2_raw_xattr {
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t xid; /* XATTR identifier number */
jint32_t version;
uint8_t xprefix;
uint8_t name_len;
jint16_t value_len;
jint32_t data_crc;
jint32_t node_crc;
uint8_t data[0];
} __attribute__((packed));
struct jffs2_raw_xref
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t ino; /* inode number */
jint32_t xid; /* XATTR identifier number */
jint32_t xseqno; /* xref sequencial number */
jint32_t node_crc;
} __attribute__((packed));
struct jffs2_raw_summary
{
jint16_t magic;
jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */
jint32_t totlen;
jint32_t hdr_crc;
jint32_t sum_num; /* number of sum entries*/
jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */
jint32_t padded; /* sum of the size of padding nodes */
jint32_t sum_crc; /* summary information crc */
jint32_t node_crc; /* node crc */
jint32_t sum[0]; /* inode summary info */
} __attribute__((packed));
union jffs2_node_union
{
struct jffs2_raw_inode i;
struct jffs2_raw_dirent d;
struct jffs2_raw_xattr x;
struct jffs2_raw_xref r;
struct jffs2_raw_summary s;
struct jffs2_unknown_node u;
};
#endif /* __LINUX_JFFS2_H__ */

View File

@@ -0,0 +1,76 @@
/*
* $Id: ftl.h,v 1.7 2005/11/07 11:14:54 gleixner Exp $
*
* Derived from (and probably identical to):
* ftl.h 1.7 1999/10/25 20:23:17
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License
* at http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and
* limitations under the License.
*
* The initial developer of the original code is David A. Hinds
* <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
* are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
*
* 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 MPL, 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 MPL or the GPL.
*/
#ifndef __MTD_FTL_USER_H__
#define __MTD_FTL_USER_H__
typedef struct erase_unit_header_t {
u_int8_t LinkTargetTuple[5];
u_int8_t DataOrgTuple[10];
u_int8_t NumTransferUnits;
u_int32_t EraseCount;
u_int16_t LogicalEUN;
u_int8_t BlockSize;
u_int8_t EraseUnitSize;
u_int16_t FirstPhysicalEUN;
u_int16_t NumEraseUnits;
u_int32_t FormattedSize;
u_int32_t FirstVMAddress;
u_int16_t NumVMPages;
u_int8_t Flags;
u_int8_t Code;
u_int32_t SerialNumber;
u_int32_t AltEUHOffset;
u_int32_t BAMOffset;
u_int8_t Reserved[12];
u_int8_t EndTuple[2];
} erase_unit_header_t;
/* Flags in erase_unit_header_t */
#define HIDDEN_AREA 0x01
#define REVERSE_POLARITY 0x02
#define DOUBLE_BAI 0x04
/* Definitions for block allocation information */
#define BLOCK_FREE(b) ((b) == 0xffffffff)
#define BLOCK_DELETED(b) (((b) == 0) || ((b) == 0xfffffffe))
#define BLOCK_TYPE(b) ((b) & 0x7f)
#define BLOCK_ADDRESS(b) ((b) & ~0x7f)
#define BLOCK_NUMBER(b) ((b) >> 9)
#define BLOCK_CONTROL 0x30
#define BLOCK_DATA 0x40
#define BLOCK_REPLACEMENT 0x60
#define BLOCK_BAD 0x70
#endif /* __MTD_FTL_USER_H__ */

View File

@@ -0,0 +1,89 @@
/*
* $Id: inftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
*
* Parts of INFTL headers shared with userspace
*
*/
#ifndef __MTD_INFTL_USER_H__
#define __MTD_INFTL_USER_H__
#define OSAK_VERSION 0x5120
#define PERCENTUSED 98
#define SECTORSIZE 512
/* Block Control Information */
struct inftl_bci {
uint8_t ECCsig[6];
uint8_t Status;
uint8_t Status1;
} __attribute__((packed));
struct inftl_unithead1 {
uint16_t virtualUnitNo;
uint16_t prevUnitNo;
uint8_t ANAC;
uint8_t NACs;
uint8_t parityPerField;
uint8_t discarded;
} __attribute__((packed));
struct inftl_unithead2 {
uint8_t parityPerField;
uint8_t ANAC;
uint16_t prevUnitNo;
uint16_t virtualUnitNo;
uint8_t NACs;
uint8_t discarded;
} __attribute__((packed));
struct inftl_unittail {
uint8_t Reserved[4];
uint16_t EraseMark;
uint16_t EraseMark1;
} __attribute__((packed));
union inftl_uci {
struct inftl_unithead1 a;
struct inftl_unithead2 b;
struct inftl_unittail c;
};
struct inftl_oob {
struct inftl_bci b;
union inftl_uci u;
};
/* INFTL Media Header */
struct INFTLPartition {
__u32 virtualUnits;
__u32 firstUnit;
__u32 lastUnit;
__u32 flags;
__u32 spareUnits;
__u32 Reserved0;
__u32 Reserved1;
} __attribute__((packed));
struct INFTLMediaHeader {
char bootRecordID[8];
__u32 NoOfBootImageBlocks;
__u32 NoOfBinaryPartitions;
__u32 NoOfBDTLPartitions;
__u32 BlockMultiplierBits;
__u32 FormatFlags;
__u32 OsakVersion;
__u32 PercentUsed;
struct INFTLPartition Partitions[4];
} __attribute__((packed));
/* Partition flag types */
#define INFTL_BINARY 0x20000000
#define INFTL_BDTL 0x40000000
#define INFTL_LAST 0x80000000
#endif /* __MTD_INFTL_USER_H__ */

View File

@@ -0,0 +1,82 @@
/*
* $Id: jffs2-user.h,v 1.1 2004/05/05 11:57:54 dwmw2 Exp $
*
* JFFS2 definitions for use in user space only
*/
#ifndef __JFFS2_USER_H__
#define __JFFS2_USER_H__
/* This file is blessed for inclusion by userspace */
#include <linux/jffs2.h>
#include <endian.h>
#include <byteswap.h>
#undef cpu_to_je16
#undef cpu_to_je32
#undef cpu_to_jemode
#undef je16_to_cpu
#undef je32_to_cpu
#undef jemode_to_cpu
extern int target_endian;
#define t16(x) ({ uint16_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_16(__b); })
#define t32(x) ({ uint32_t __b = (x); (target_endian==__BYTE_ORDER)?__b:bswap_32(__b); })
#define cpu_to_je16(x) ((jint16_t){t16(x)})
#define cpu_to_je32(x) ((jint32_t){t32(x)})
#define cpu_to_jemode(x) ((jmode_t){t32(x)})
#define je16_to_cpu(x) (t16((x).v16))
#define je32_to_cpu(x) (t32((x).v32))
#define jemode_to_cpu(x) (t32((x).m))
#define le16_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
#define le32_to_cpu(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
#define cpu_to_le16(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_16(x))
#define cpu_to_le32(x) (__BYTE_ORDER==__LITTLE_ENDIAN ? (x) : bswap_32(x))
/* XATTR/POSIX-ACL related definition */
/* Namespaces copied from xattr.h and posix_acl_xattr.h */
#define XATTR_USER_PREFIX "user."
#define XATTR_USER_PREFIX_LEN (sizeof (XATTR_USER_PREFIX) - 1)
#define XATTR_SECURITY_PREFIX "security."
#define XATTR_SECURITY_PREFIX_LEN (sizeof (XATTR_SECURITY_PREFIX) - 1)
#define POSIX_ACL_XATTR_ACCESS "system.posix_acl_access"
#define POSIX_ACL_XATTR_ACCESS_LEN (sizeof (POSIX_ACL_XATTR_ACCESS) - 1)
#define POSIX_ACL_XATTR_DEFAULT "system.posix_acl_default"
#define POSIX_ACL_XATTR_DEFAULT_LEN (sizeof (POSIX_ACL_XATTR_DEFAULT) - 1)
#define XATTR_TRUSTED_PREFIX "trusted."
#define XATTR_TRUSTED_PREFIX_LEN (sizeof (XATTR_TRUSTED_PREFIX) - 1)
struct jffs2_acl_entry {
jint16_t e_tag;
jint16_t e_perm;
jint32_t e_id;
};
struct jffs2_acl_entry_short {
jint16_t e_tag;
jint16_t e_perm;
};
struct jffs2_acl_header {
jint32_t a_version;
};
/* copied from include/linux/posix_acl_xattr.h */
#define POSIX_ACL_XATTR_VERSION 0x0002
struct posix_acl_xattr_entry {
uint16_t e_tag;
uint16_t e_perm;
uint32_t e_id;
};
struct posix_acl_xattr_header {
uint32_t a_version;
struct posix_acl_xattr_entry a_entries[0];
};
#endif /* __JFFS2_USER_H__ */

View File

@@ -0,0 +1,277 @@
/*
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org> et al.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __MTD_ABI_H__
#define __MTD_ABI_H__
#include <linux/types.h>
struct erase_info_user {
__u32 start;
__u32 length;
};
struct erase_info_user64 {
__u64 start;
__u64 length;
};
struct mtd_oob_buf {
__u32 start;
__u32 length;
unsigned char *ptr;
};
struct mtd_oob_buf64 {
__u64 start;
__u32 pad;
__u32 length;
__u64 usr_ptr;
};
/**
* MTD operation modes
*
* @MTD_OPS_PLACE_OOB: OOB data are placed at the given offset (default)
* @MTD_OPS_AUTO_OOB: OOB data are automatically placed at the free areas
* which are defined by the internal ecclayout
* @MTD_OPS_RAW: data are transferred as-is, with no error correction;
* this mode implies %MTD_OPS_PLACE_OOB
*
* These modes can be passed to ioctl(MEMWRITE) and are also used internally.
* See notes on "MTD file modes" for discussion on %MTD_OPS_RAW vs.
* %MTD_FILE_MODE_RAW.
*/
enum {
MTD_OPS_PLACE_OOB = 0,
MTD_OPS_AUTO_OOB = 1,
MTD_OPS_RAW = 2,
};
/**
* struct mtd_write_req - data structure for requesting a write operation
*
* @start: start address
* @len: length of data buffer
* @ooblen: length of OOB buffer
* @usr_data: user-provided data buffer
* @usr_oob: user-provided OOB buffer
* @mode: MTD mode (see "MTD operation modes")
* @padding: reserved, must be set to 0
*
* This structure supports ioctl(MEMWRITE) operations, allowing data and/or OOB
* writes in various modes. To write to OOB-only, set @usr_data == NULL, and to
* write data-only, set @usr_oob == NULL. However, setting both @usr_data and
* @usr_oob to NULL is not allowed.
*/
struct mtd_write_req {
__u64 start;
__u64 len;
__u64 ooblen;
__u64 usr_data;
__u64 usr_oob;
__u8 mode;
__u8 padding[7];
};
#define MTD_ABSENT 0
#define MTD_RAM 1
#define MTD_ROM 2
#define MTD_NORFLASH 3
#define MTD_NANDFLASH 4
#define MTD_DATAFLASH 6
#define MTD_UBIVOLUME 7
#define MTD_MLCNANDFLASH 8
#define MTD_WRITEABLE 0x400 /* Device is writeable */
#define MTD_BIT_WRITEABLE 0x800 /* Single bits can be flipped */
#define MTD_NO_ERASE 0x1000 /* No erase necessary */
#define MTD_POWERUP_LOCK 0x2000 /* Always locked after reset */
/* Some common devices / combinations of capabilities */
#define MTD_CAP_ROM 0
#define MTD_CAP_RAM (MTD_WRITEABLE | MTD_BIT_WRITEABLE | MTD_NO_ERASE)
#define MTD_CAP_NORFLASH (MTD_WRITEABLE | MTD_BIT_WRITEABLE)
#define MTD_CAP_NANDFLASH (MTD_WRITEABLE)
/* Obsolete ECC byte placement modes (used with obsolete MEMGETOOBSEL) */
#define MTD_NANDECC_OFF 0 // Switch off ECC (Not recommended)
#define MTD_NANDECC_PLACE 1 // Use the given placement in the structure (YAFFS1 legacy mode)
#define MTD_NANDECC_AUTOPLACE 2 // Use the default placement scheme
#define MTD_NANDECC_PLACEONLY 3 // Use the given placement in the structure (Do not store ecc result on read)
#define MTD_NANDECC_AUTOPL_USR 4 // Use the given autoplacement scheme rather than using the default
/* OTP mode selection */
#define MTD_OTP_OFF 0
#define MTD_OTP_FACTORY 1
#define MTD_OTP_USER 2
struct mtd_info_user {
__u8 type;
__u32 flags;
__u32 size; /* Total size of the MTD */
__u32 erasesize;
__u32 writesize;
__u32 oobsize; /* Amount of OOB data per block (e.g. 16) */
__u64 padding; /* Old obsolete field; do not use */
};
struct region_info_user {
__u32 offset; /* At which this region starts,
* from the beginning of the MTD */
__u32 erasesize; /* For this region */
__u32 numblocks; /* Number of blocks in this region */
__u32 regionindex;
};
struct otp_info {
__u32 start;
__u32 length;
__u32 locked;
};
/*
* Note, the following ioctl existed in the past and was removed:
* #define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo)
* Try to avoid adding a new ioctl with the same ioctl number.
*/
/* Get basic MTD characteristics info (better to use sysfs) */
#define MEMGETINFO _IOR('M', 1, struct mtd_info_user)
/* Erase segment of MTD */
#define MEMERASE _IOW('M', 2, struct erase_info_user)
/* Write out-of-band data from MTD */
#define MEMWRITEOOB _IOWR('M', 3, struct mtd_oob_buf)
/* Read out-of-band data from MTD */
#define MEMREADOOB _IOWR('M', 4, struct mtd_oob_buf)
/* Lock a chip (for MTD that supports it) */
#define MEMLOCK _IOW('M', 5, struct erase_info_user)
/* Unlock a chip (for MTD that supports it) */
#define MEMUNLOCK _IOW('M', 6, struct erase_info_user)
/* Get the number of different erase regions */
#define MEMGETREGIONCOUNT _IOR('M', 7, int)
/* Get information about the erase region for a specific index */
#define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user)
/* Get info about OOB modes (e.g., RAW, PLACE, AUTO) - legacy interface */
#define MEMGETOOBSEL _IOR('M', 10, struct nand_oobinfo)
/* Check if an eraseblock is bad */
#define MEMGETBADBLOCK _IOW('M', 11, __kernel_loff_t)
/* Mark an eraseblock as bad */
#define MEMSETBADBLOCK _IOW('M', 12, __kernel_loff_t)
/* Set OTP (One-Time Programmable) mode (factory vs. user) */
#define OTPSELECT _IOR('M', 13, int)
/* Get number of OTP (One-Time Programmable) regions */
#define OTPGETREGIONCOUNT _IOW('M', 14, int)
/* Get all OTP (One-Time Programmable) info about MTD */
#define OTPGETREGIONINFO _IOW('M', 15, struct otp_info)
/* Lock a given range of user data (must be in mode %MTD_FILE_MODE_OTP_USER) */
#define OTPLOCK _IOR('M', 16, struct otp_info)
/* Get ECC layout (deprecated) */
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout_user)
/* Get statistics about corrected/uncorrected errors */
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
/* Set MTD mode on a per-file-descriptor basis (see "MTD file modes") */
#define MTDFILEMODE _IO('M', 19)
/* Erase segment of MTD (supports 64-bit address) */
#define MEMERASE64 _IOW('M', 20, struct erase_info_user64)
/* Write data to OOB (64-bit version) */
#define MEMWRITEOOB64 _IOWR('M', 21, struct mtd_oob_buf64)
/* Read data from OOB (64-bit version) */
#define MEMREADOOB64 _IOWR('M', 22, struct mtd_oob_buf64)
/* Check if chip is locked (for MTD that supports it) */
#define MEMISLOCKED _IOR('M', 23, struct erase_info_user)
/*
* Most generic write interface; can write in-band and/or out-of-band in various
* modes (see "struct mtd_write_req")
*/
#define MEMWRITE _IOWR('M', 24, struct mtd_write_req)
/*
* Obsolete legacy interface. Keep it in order not to break userspace
* interfaces
*/
struct nand_oobinfo {
__u32 useecc;
__u32 eccbytes;
__u32 oobfree[8][2];
__u32 eccpos[32];
};
struct nand_oobfree {
__u32 offset;
__u32 length;
};
#define MTD_MAX_OOBFREE_ENTRIES 8
#define MTD_MAX_ECCPOS_ENTRIES 64
/*
* OBSOLETE: ECC layout control structure. Exported to user-space via ioctl
* ECCGETLAYOUT for backwards compatbility and should not be mistaken as a
* complete set of ECC information. The ioctl truncates the larger internal
* structure to retain binary compatibility with the static declaration of the
* ioctl. Note that the "MTD_MAX_..._ENTRIES" macros represent the max size of
* the user struct, not the MAX size of the internal struct nand_ecclayout.
*/
struct nand_ecclayout_user {
__u32 eccbytes;
__u32 eccpos[MTD_MAX_ECCPOS_ENTRIES];
__u32 oobavail;
struct nand_oobfree oobfree[MTD_MAX_OOBFREE_ENTRIES];
};
/**
* struct mtd_ecc_stats - error correction stats
*
* @corrected: number of corrected bits
* @failed: number of uncorrectable errors
* @badblocks: number of bad blocks in this partition
* @bbtblocks: number of blocks reserved for bad block tables
*/
struct mtd_ecc_stats {
__u32 corrected;
__u32 failed;
__u32 badblocks;
__u32 bbtblocks;
};
/*
* MTD file modes - for read/write access to MTD
*
* @MTD_FILE_MODE_NORMAL: OTP disabled, ECC enabled
* @MTD_FILE_MODE_OTP_FACTORY: OTP enabled in factory mode
* @MTD_FILE_MODE_OTP_USER: OTP enabled in user mode
* @MTD_FILE_MODE_RAW: OTP disabled, ECC disabled
*
* These modes can be set via ioctl(MTDFILEMODE). The mode mode will be retained
* separately for each open file descriptor.
*
* Note: %MTD_FILE_MODE_RAW provides the same functionality as %MTD_OPS_RAW -
* raw access to the flash, without error correction or autoplacement schemes.
* Wherever possible, the MTD_OPS_* mode will override the MTD_FILE_MODE_* mode
* (e.g., when using ioctl(MEMWRITE)), but in some cases, the MTD_FILE_MODE is
* used out of necessity (e.g., `write()', ioctl(MEMWRITEOOB64)).
*/
enum mtd_file_modes {
MTD_FILE_MODE_NORMAL = MTD_OTP_OFF,
MTD_FILE_MODE_OTP_FACTORY = MTD_OTP_FACTORY,
MTD_FILE_MODE_OTP_USER = MTD_OTP_USER,
MTD_FILE_MODE_RAW,
};
#endif /* __MTD_ABI_H__ */

View File

@@ -0,0 +1,34 @@
/*
* Copyright © 1999-2010 David Woodhouse <dwmw2@infradead.org>
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef __MTD_USER_H__
#define __MTD_USER_H__
#include <stdint.h>
/* This file is blessed for inclusion by userspace */
#include <mtd/mtd-abi.h>
typedef struct mtd_info_user mtd_info_t;
typedef struct erase_info_user erase_info_t;
typedef struct region_info_user region_info_t;
typedef struct nand_oobinfo nand_oobinfo_t;
typedef struct nand_ecclayout_user nand_ecclayout_t;
#endif /* __MTD_USER_H__ */

View File

@@ -0,0 +1,76 @@
/*
* $Id: nftl-user.h,v 1.2 2005/11/07 11:14:56 gleixner Exp $
*
* Parts of NFTL headers shared with userspace
*
*/
#ifndef __MTD_NFTL_USER_H__
#define __MTD_NFTL_USER_H__
/* Block Control Information */
struct nftl_bci {
unsigned char ECCSig[6];
uint8_t Status;
uint8_t Status1;
}__attribute__((packed));
/* Unit Control Information */
struct nftl_uci0 {
uint16_t VirtUnitNum;
uint16_t ReplUnitNum;
uint16_t SpareVirtUnitNum;
uint16_t SpareReplUnitNum;
} __attribute__((packed));
struct nftl_uci1 {
uint32_t WearInfo;
uint16_t EraseMark;
uint16_t EraseMark1;
} __attribute__((packed));
struct nftl_uci2 {
uint16_t FoldMark;
uint16_t FoldMark1;
uint32_t unused;
} __attribute__((packed));
union nftl_uci {
struct nftl_uci0 a;
struct nftl_uci1 b;
struct nftl_uci2 c;
};
struct nftl_oob {
struct nftl_bci b;
union nftl_uci u;
};
/* NFTL Media Header */
struct NFTLMediaHeader {
char DataOrgID[6];
uint16_t NumEraseUnits;
uint16_t FirstPhysicalEUN;
uint32_t FormattedSize;
unsigned char UnitSizeFactor;
} __attribute__((packed));
#define MAX_ERASE_ZONES (8192 - 512)
#define ERASE_MARK 0x3c69
#define SECTOR_FREE 0xff
#define SECTOR_USED 0x55
#define SECTOR_IGNORE 0x11
#define SECTOR_DELETED 0x00
#define FOLD_MARK_IN_PROGRESS 0x5555
#define ZONE_GOOD 0xff
#define ZONE_BAD_ORIGINAL 0
#define ZONE_BAD_MARKED 7
#endif /* __MTD_NFTL_USER_H__ */

View File

@@ -0,0 +1,378 @@
/*
* Copyright (c) International Business Machines Corp., 2006
*
* 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
*
* Authors: Artem Bityutskiy (Битюцкий Артём)
* Thomas Gleixner
* Frank Haverkamp
* Oliver Lohmann
* Andreas Arnez
*/
/*
* This file defines the layout of UBI headers and all the other UBI on-flash
* data structures.
*/
#ifndef __UBI_MEDIA_H__
#define __UBI_MEDIA_H__
#include <asm/byteorder.h>
/* The version of UBI images supported by this implementation */
#define UBI_VERSION 1
/* The highest erase counter value supported by this implementation */
#define UBI_MAX_ERASECOUNTER 0x7FFFFFFF
/* The initial CRC32 value used when calculating CRC checksums */
#define UBI_CRC32_INIT 0xFFFFFFFFU
/* Erase counter header magic number (ASCII "UBI#") */
#define UBI_EC_HDR_MAGIC 0x55424923
/* Volume identifier header magic number (ASCII "UBI!") */
#define UBI_VID_HDR_MAGIC 0x55424921
/*
* Volume type constants used in the volume identifier header.
*
* @UBI_VID_DYNAMIC: dynamic volume
* @UBI_VID_STATIC: static volume
*/
enum {
UBI_VID_DYNAMIC = 1,
UBI_VID_STATIC = 2
};
/*
* Volume flags used in the volume table record.
*
* @UBI_VTBL_AUTORESIZE_FLG: auto-resize this volume
*
* %UBI_VTBL_AUTORESIZE_FLG flag can be set only for one volume in the volume
* table. UBI automatically re-sizes the volume which has this flag and makes
* the volume to be of largest possible size. This means that if after the
* initialization UBI finds out that there are available physical eraseblocks
* present on the device, it automatically appends all of them to the volume
* (the physical eraseblocks reserved for bad eraseblocks handling and other
* reserved physical eraseblocks are not taken). So, if there is a volume with
* the %UBI_VTBL_AUTORESIZE_FLG flag set, the amount of available logical
* eraseblocks will be zero after UBI is loaded, because all of them will be
* reserved for this volume. Note, the %UBI_VTBL_AUTORESIZE_FLG bit is cleared
* after the volume had been initialized.
*
* The auto-resize feature is useful for device production purposes. For
* example, different NAND flash chips may have different amount of initial bad
* eraseblocks, depending of particular chip instance. Manufacturers of NAND
* chips usually guarantee that the amount of initial bad eraseblocks does not
* exceed certain percent, e.g. 2%. When one creates an UBI image which will be
* flashed to the end devices in production, he does not know the exact amount
* of good physical eraseblocks the NAND chip on the device will have, but this
* number is required to calculate the volume sized and put them to the volume
* table of the UBI image. In this case, one of the volumes (e.g., the one
* which will store the root file system) is marked as "auto-resizable", and
* UBI will adjust its size on the first boot if needed.
*
* Note, first UBI reserves some amount of physical eraseblocks for bad
* eraseblock handling, and then re-sizes the volume, not vice-versa. This
* means that the pool of reserved physical eraseblocks will always be present.
*/
enum {
UBI_VTBL_AUTORESIZE_FLG = 0x01,
};
/*
* Compatibility constants used by internal volumes.
*
* @UBI_COMPAT_DELETE: delete this internal volume before anything is written
* to the flash
* @UBI_COMPAT_RO: attach this device in read-only mode
* @UBI_COMPAT_PRESERVE: preserve this internal volume - do not touch its
* physical eraseblocks, don't allow the wear-leveling
* sub-system to move them
* @UBI_COMPAT_REJECT: reject this UBI image
*/
enum {
UBI_COMPAT_DELETE = 1,
UBI_COMPAT_RO = 2,
UBI_COMPAT_PRESERVE = 4,
UBI_COMPAT_REJECT = 5
};
/* Sizes of UBI headers */
#define UBI_EC_HDR_SIZE sizeof(struct ubi_ec_hdr)
#define UBI_VID_HDR_SIZE sizeof(struct ubi_vid_hdr)
/* Sizes of UBI headers without the ending CRC */
#define UBI_EC_HDR_SIZE_CRC (UBI_EC_HDR_SIZE - sizeof(__be32))
#define UBI_VID_HDR_SIZE_CRC (UBI_VID_HDR_SIZE - sizeof(__be32))
/**
* struct ubi_ec_hdr - UBI erase counter header.
* @magic: erase counter header magic number (%UBI_EC_HDR_MAGIC)
* @version: version of UBI implementation which is supposed to accept this
* UBI image
* @padding1: reserved for future, zeroes
* @ec: the erase counter
* @vid_hdr_offset: where the VID header starts
* @data_offset: where the user data start
* @image_seq: image sequence number
* @padding2: reserved for future, zeroes
* @hdr_crc: erase counter header CRC checksum
*
* The erase counter header takes 64 bytes and has a plenty of unused space for
* future usage. The unused fields are zeroed. The @version field is used to
* indicate the version of UBI implementation which is supposed to be able to
* work with this UBI image. If @version is greater than the current UBI
* version, the image is rejected. This may be useful in future if something
* is changed radically. This field is duplicated in the volume identifier
* header.
*
* The @vid_hdr_offset and @data_offset fields contain the offset of the the
* volume identifier header and user data, relative to the beginning of the
* physical eraseblock. These values have to be the same for all physical
* eraseblocks.
*
* The @image_seq field is used to validate a UBI image that has been prepared
* for a UBI device. The @image_seq value can be any value, but it must be the
* same on all eraseblocks. UBI will ensure that all new erase counter headers
* also contain this value, and will check the value when scanning at start-up.
* One way to make use of @image_seq is to increase its value by one every time
* an image is flashed over an existing image, then, if the flashing does not
* complete, UBI will detect the error when scanning.
*/
struct ubi_ec_hdr {
__be32 magic;
__u8 version;
__u8 padding1[3];
__be64 ec; /* Warning: the current limit is 31-bit anyway! */
__be32 vid_hdr_offset;
__be32 data_offset;
__be32 image_seq;
__u8 padding2[32];
__be32 hdr_crc;
} __attribute__ ((packed));
/**
* struct ubi_vid_hdr - on-flash UBI volume identifier header.
* @magic: volume identifier header magic number (%UBI_VID_HDR_MAGIC)
* @version: UBI implementation version which is supposed to accept this UBI
* image (%UBI_VERSION)
* @vol_type: volume type (%UBI_VID_DYNAMIC or %UBI_VID_STATIC)
* @copy_flag: if this logical eraseblock was copied from another physical
* eraseblock (for wear-leveling reasons)
* @compat: compatibility of this volume (%0, %UBI_COMPAT_DELETE,
* %UBI_COMPAT_IGNORE, %UBI_COMPAT_PRESERVE, or %UBI_COMPAT_REJECT)
* @vol_id: ID of this volume
* @lnum: logical eraseblock number
* @padding1: reserved for future, zeroes
* @data_size: how many bytes of data this logical eraseblock contains
* @used_ebs: total number of used logical eraseblocks in this volume
* @data_pad: how many bytes at the end of this physical eraseblock are not
* used
* @data_crc: CRC checksum of the data stored in this logical eraseblock
* @padding2: reserved for future, zeroes
* @sqnum: sequence number
* @padding3: reserved for future, zeroes
* @hdr_crc: volume identifier header CRC checksum
*
* The @sqnum is the value of the global sequence counter at the time when this
* VID header was created. The global sequence counter is incremented each time
* UBI writes a new VID header to the flash, i.e. when it maps a logical
* eraseblock to a new physical eraseblock. The global sequence counter is an
* unsigned 64-bit integer and we assume it never overflows. The @sqnum
* (sequence number) is used to distinguish between older and newer versions of
* logical eraseblocks.
*
* There are 2 situations when there may be more than one physical eraseblock
* corresponding to the same logical eraseblock, i.e., having the same @vol_id
* and @lnum values in the volume identifier header. Suppose we have a logical
* eraseblock L and it is mapped to the physical eraseblock P.
*
* 1. Because UBI may erase physical eraseblocks asynchronously, the following
* situation is possible: L is asynchronously erased, so P is scheduled for
* erasure, then L is written to,i.e. mapped to another physical eraseblock P1,
* so P1 is written to, then an unclean reboot happens. Result - there are 2
* physical eraseblocks P and P1 corresponding to the same logical eraseblock
* L. But P1 has greater sequence number, so UBI picks P1 when it attaches the
* flash.
*
* 2. From time to time UBI moves logical eraseblocks to other physical
* eraseblocks for wear-leveling reasons. If, for example, UBI moves L from P
* to P1, and an unclean reboot happens before P is physically erased, there
* are two physical eraseblocks P and P1 corresponding to L and UBI has to
* select one of them when the flash is attached. The @sqnum field says which
* PEB is the original (obviously P will have lower @sqnum) and the copy. But
* it is not enough to select the physical eraseblock with the higher sequence
* number, because the unclean reboot could have happen in the middle of the
* copying process, so the data in P is corrupted. It is also not enough to
* just select the physical eraseblock with lower sequence number, because the
* data there may be old (consider a case if more data was added to P1 after
* the copying). Moreover, the unclean reboot may happen when the erasure of P
* was just started, so it result in unstable P, which is "mostly" OK, but
* still has unstable bits.
*
* UBI uses the @copy_flag field to indicate that this logical eraseblock is a
* copy. UBI also calculates data CRC when the data is moved and stores it at
* the @data_crc field of the copy (P1). So when UBI needs to pick one physical
* eraseblock of two (P or P1), the @copy_flag of the newer one (P1) is
* examined. If it is cleared, the situation* is simple and the newer one is
* picked. If it is set, the data CRC of the copy (P1) is examined. If the CRC
* checksum is correct, this physical eraseblock is selected (P1). Otherwise
* the older one (P) is selected.
*
* There are 2 sorts of volumes in UBI: user volumes and internal volumes.
* Internal volumes are not seen from outside and are used for various internal
* UBI purposes. In this implementation there is only one internal volume - the
* layout volume. Internal volumes are the main mechanism of UBI extensions.
* For example, in future one may introduce a journal internal volume. Internal
* volumes have their own reserved range of IDs.
*
* The @compat field is only used for internal volumes and contains the "degree
* of their compatibility". It is always zero for user volumes. This field
* provides a mechanism to introduce UBI extensions and to be still compatible
* with older UBI binaries. For example, if someone introduced a journal in
* future, he would probably use %UBI_COMPAT_DELETE compatibility for the
* journal volume. And in this case, older UBI binaries, which know nothing
* about the journal volume, would just delete this volume and work perfectly
* fine. This is similar to what Ext2fs does when it is fed by an Ext3fs image
* - it just ignores the Ext3fs journal.
*
* The @data_crc field contains the CRC checksum of the contents of the logical
* eraseblock if this is a static volume. In case of dynamic volumes, it does
* not contain the CRC checksum as a rule. The only exception is when the
* data of the physical eraseblock was moved by the wear-leveling sub-system,
* then the wear-leveling sub-system calculates the data CRC and stores it in
* the @data_crc field. And of course, the @copy_flag is %in this case.
*
* The @data_size field is used only for static volumes because UBI has to know
* how many bytes of data are stored in this eraseblock. For dynamic volumes,
* this field usually contains zero. The only exception is when the data of the
* physical eraseblock was moved to another physical eraseblock for
* wear-leveling reasons. In this case, UBI calculates CRC checksum of the
* contents and uses both @data_crc and @data_size fields. In this case, the
* @data_size field contains data size.
*
* The @used_ebs field is used only for static volumes and indicates how many
* eraseblocks the data of the volume takes. For dynamic volumes this field is
* not used and always contains zero.
*
* The @data_pad is calculated when volumes are created using the alignment
* parameter. So, effectively, the @data_pad field reduces the size of logical
* eraseblocks of this volume. This is very handy when one uses block-oriented
* software (say, cramfs) on top of the UBI volume.
*/
struct ubi_vid_hdr {
__be32 magic;
__u8 version;
__u8 vol_type;
__u8 copy_flag;
__u8 compat;
__be32 vol_id;
__be32 lnum;
__be32 leb_ver;
__be32 data_size;
__be32 used_ebs;
__be32 data_pad;
__be32 data_crc;
__u8 padding2[4];
__be64 sqnum;
__u8 padding3[12];
__be32 hdr_crc;
} __attribute__ ((packed));
/* Internal UBI volumes count */
#define UBI_INT_VOL_COUNT 1
/*
* Starting ID of internal volumes. There is reserved room for 4096 internal
* volumes.
*/
#define UBI_INTERNAL_VOL_START (0x7FFFFFFF - 4096)
/* The layout volume contains the volume table */
#define UBI_LAYOUT_VOLUME_ID UBI_INTERNAL_VOL_START
#define UBI_LAYOUT_VOLUME_TYPE UBI_VID_DYNAMIC
#define UBI_LAYOUT_VOLUME_ALIGN 1
#define UBI_LAYOUT_VOLUME_EBS 2
#define UBI_LAYOUT_VOLUME_NAME "layout volume"
#define UBI_LAYOUT_VOLUME_COMPAT UBI_COMPAT_REJECT
/* The maximum number of volumes per one UBI device */
#define UBI_MAX_VOLUMES 128
/* The maximum volume name length */
#define UBI_VOL_NAME_MAX 127
/* Size of the volume table record */
#define UBI_VTBL_RECORD_SIZE sizeof(struct ubi_vtbl_record)
/* Size of the volume table record without the ending CRC */
#define UBI_VTBL_RECORD_SIZE_CRC (UBI_VTBL_RECORD_SIZE - sizeof(__be32))
/**
* struct ubi_vtbl_record - a record in the volume table.
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
* @alignment: volume alignment
* @data_pad: how many bytes are unused at the end of the each physical
* eraseblock to satisfy the requested alignment
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
* @upd_marker: if volume update was started but not finished
* @name_len: volume name length
* @name: the volume name
* @flags: volume flags (%UBI_VTBL_AUTORESIZE_FLG)
* @padding: reserved, zeroes
* @crc: a CRC32 checksum of the record
*
* The volume table records are stored in the volume table, which is stored in
* the layout volume. The layout volume consists of 2 logical eraseblock, each
* of which contains a copy of the volume table (i.e., the volume table is
* duplicated). The volume table is an array of &struct ubi_vtbl_record
* objects indexed by the volume ID.
*
* If the size of the logical eraseblock is large enough to fit
* %UBI_MAX_VOLUMES records, the volume table contains %UBI_MAX_VOLUMES
* records. Otherwise, it contains as many records as it can fit (i.e., size of
* logical eraseblock divided by sizeof(struct ubi_vtbl_record)).
*
* The @upd_marker flag is used to implement volume update. It is set to %1
* before update and set to %0 after the update. So if the update operation was
* interrupted, UBI knows that the volume is corrupted.
*
* The @alignment field is specified when the volume is created and cannot be
* later changed. It may be useful, for example, when a block-oriented file
* system works on top of UBI. The @data_pad field is calculated using the
* logical eraseblock size and @alignment. The alignment must be multiple to the
* minimal flash I/O unit. If @alignment is 1, all the available space of
* the physical eraseblocks is used.
*
* Empty records contain all zeroes and the CRC checksum of those zeroes.
*/
struct ubi_vtbl_record {
__be32 reserved_pebs;
__be32 alignment;
__be32 data_pad;
__u8 vol_type;
__u8 upd_marker;
__be16 name_len;
__u8 name[UBI_VOL_NAME_MAX+1];
__u8 flags;
__u8 padding[23];
__be32 crc;
} __attribute__ ((packed));
#endif /* !__UBI_MEDIA_H__ */

View File

@@ -0,0 +1,418 @@
/*
* Copyright © International Business Machines Corp., 2006
*
* 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
*
* Author: Artem Bityutskiy (Битюцкий Артём)
*/
#ifndef __UBI_USER_H__
#define __UBI_USER_H__
/*
* UBI device creation (the same as MTD device attachment)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* MTD devices may be attached using %UBI_IOCATT ioctl command of the UBI
* control device. The caller has to properly fill and pass
* &struct ubi_attach_req object - UBI will attach the MTD device specified in
* the request and return the newly created UBI device number as the ioctl
* return value.
*
* UBI device deletion (the same as MTD device detachment)
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* An UBI device maybe deleted with %UBI_IOCDET ioctl command of the UBI
* control device.
*
* UBI volume creation
* ~~~~~~~~~~~~~~~~~~~
*
* UBI volumes are created via the %UBI_IOCMKVOL ioctl command of UBI character
* device. A &struct ubi_mkvol_req object has to be properly filled and a
* pointer to it has to be passed to the ioctl.
*
* UBI volume deletion
* ~~~~~~~~~~~~~~~~~~~
*
* To delete a volume, the %UBI_IOCRMVOL ioctl command of the UBI character
* device should be used. A pointer to the 32-bit volume ID hast to be passed
* to the ioctl.
*
* UBI volume re-size
* ~~~~~~~~~~~~~~~~~~
*
* To re-size a volume, the %UBI_IOCRSVOL ioctl command of the UBI character
* device should be used. A &struct ubi_rsvol_req object has to be properly
* filled and a pointer to it has to be passed to the ioctl.
*
* UBI volumes re-name
* ~~~~~~~~~~~~~~~~~~~
*
* To re-name several volumes atomically at one go, the %UBI_IOCRNVOL command
* of the UBI character device should be used. A &struct ubi_rnvol_req object
* has to be properly filled and a pointer to it has to be passed to the ioctl.
*
* UBI volume update
* ~~~~~~~~~~~~~~~~~
*
* Volume update should be done via the %UBI_IOCVOLUP ioctl command of the
* corresponding UBI volume character device. A pointer to a 64-bit update
* size should be passed to the ioctl. After this, UBI expects user to write
* this number of bytes to the volume character device. The update is finished
* when the claimed number of bytes is passed. So, the volume update sequence
* is something like:
*
* fd = open("/dev/my_volume");
* ioctl(fd, UBI_IOCVOLUP, &image_size);
* write(fd, buf, image_size);
* close(fd);
*
* Logical eraseblock erase
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
* To erase a logical eraseblock, the %UBI_IOCEBER ioctl command of the
* corresponding UBI volume character device should be used. This command
* unmaps the requested logical eraseblock, makes sure the corresponding
* physical eraseblock is successfully erased, and returns.
*
* Atomic logical eraseblock change
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Atomic logical eraseblock change operation is called using the %UBI_IOCEBCH
* ioctl command of the corresponding UBI volume character device. A pointer to
* a &struct ubi_leb_change_req object has to be passed to the ioctl. Then the
* user is expected to write the requested amount of bytes (similarly to what
* should be done in case of the "volume update" ioctl).
*
* Logical eraseblock map
* ~~~~~~~~~~~~~~~~~~~~~
*
* To map a logical eraseblock to a physical eraseblock, the %UBI_IOCEBMAP
* ioctl command should be used. A pointer to a &struct ubi_map_req object is
* expected to be passed. The ioctl maps the requested logical eraseblock to
* a physical eraseblock and returns. Only non-mapped logical eraseblocks can
* be mapped. If the logical eraseblock specified in the request is already
* mapped to a physical eraseblock, the ioctl fails and returns error.
*
* Logical eraseblock unmap
* ~~~~~~~~~~~~~~~~~~~~~~~~
*
* To unmap a logical eraseblock to a physical eraseblock, the %UBI_IOCEBUNMAP
* ioctl command should be used. The ioctl unmaps the logical eraseblocks,
* schedules corresponding physical eraseblock for erasure, and returns. Unlike
* the "LEB erase" command, it does not wait for the physical eraseblock being
* erased. Note, the side effect of this is that if an unclean reboot happens
* after the unmap ioctl returns, you may find the LEB mapped again to the same
* physical eraseblock after the UBI is run again.
*
* Check if logical eraseblock is mapped
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* To check if a logical eraseblock is mapped to a physical eraseblock, the
* %UBI_IOCEBISMAP ioctl command should be used. It returns %0 if the LEB is
* not mapped, and %1 if it is mapped.
*
* Set an UBI volume property
* ~~~~~~~~~~~~~~~~~~~~~~~~~
*
* To set an UBI volume property the %UBI_IOCSETPROP ioctl command should be
* used. A pointer to a &struct ubi_set_vol_prop_req object is expected to be
* passed. The object describes which property should be set, and to which value
* it should be set.
*/
/*
* When a new UBI volume or UBI device is created, users may either specify the
* volume/device number they want to create or to let UBI automatically assign
* the number using these constants.
*/
#define UBI_VOL_NUM_AUTO (-1)
#define UBI_DEV_NUM_AUTO (-1)
/* Maximum volume name length */
#define UBI_MAX_VOLUME_NAME 127
/* ioctl commands of UBI character devices */
#define UBI_IOC_MAGIC 'o'
/* Create an UBI volume */
#define UBI_IOCMKVOL _IOW(UBI_IOC_MAGIC, 0, struct ubi_mkvol_req)
/* Remove an UBI volume */
#define UBI_IOCRMVOL _IOW(UBI_IOC_MAGIC, 1, int32_t)
/* Re-size an UBI volume */
#define UBI_IOCRSVOL _IOW(UBI_IOC_MAGIC, 2, struct ubi_rsvol_req)
/* Re-name volumes */
#define UBI_IOCRNVOL _IOW(UBI_IOC_MAGIC, 3, struct ubi_rnvol_req)
/* ioctl commands of the UBI control character device */
#define UBI_CTRL_IOC_MAGIC 'o'
/* Attach an MTD device */
#define UBI_IOCATT _IOW(UBI_CTRL_IOC_MAGIC, 64, struct ubi_attach_req)
/* Detach an MTD device */
#define UBI_IOCDET _IOW(UBI_CTRL_IOC_MAGIC, 65, int32_t)
/* ioctl commands of UBI volume character devices */
#define UBI_VOL_IOC_MAGIC 'O'
/* Start UBI volume update */
#define UBI_IOCVOLUP _IOW(UBI_VOL_IOC_MAGIC, 0, int64_t)
/* LEB erasure command, used for debugging, disabled by default */
#define UBI_IOCEBER _IOW(UBI_VOL_IOC_MAGIC, 1, int32_t)
/* Atomic LEB change command */
#define UBI_IOCEBCH _IOW(UBI_VOL_IOC_MAGIC, 2, int32_t)
/* Map LEB command */
#define UBI_IOCEBMAP _IOW(UBI_VOL_IOC_MAGIC, 3, struct ubi_map_req)
/* Unmap LEB command */
#define UBI_IOCEBUNMAP _IOW(UBI_VOL_IOC_MAGIC, 4, int32_t)
/* Check if LEB is mapped command */
#define UBI_IOCEBISMAP _IOR(UBI_VOL_IOC_MAGIC, 5, int32_t)
/* Set an UBI volume property */
#define UBI_IOCSETVOLPROP _IOW(UBI_VOL_IOC_MAGIC, 6, \
struct ubi_set_vol_prop_req)
/* Maximum MTD device name length supported by UBI */
#define MAX_UBI_MTD_NAME_LEN 127
/* Maximum amount of UBI volumes that can be re-named at one go */
#define UBI_MAX_RNVOL 32
/*
* UBI volume type constants.
*
* @UBI_DYNAMIC_VOLUME: dynamic volume
* @UBI_STATIC_VOLUME: static volume
*/
enum {
UBI_DYNAMIC_VOLUME = 3,
UBI_STATIC_VOLUME = 4,
};
/*
* UBI set volume property ioctl constants.
*
* @UBI_VOL_PROP_DIRECT_WRITE: allow (any non-zero value) or disallow (value 0)
* user to directly write and erase individual
* eraseblocks on dynamic volumes
*/
enum {
UBI_VOL_PROP_DIRECT_WRITE = 1,
};
/**
* struct ubi_attach_req - attach MTD device request.
* @ubi_num: UBI device number to create
* @mtd_num: MTD device number to attach
* @vid_hdr_offset: VID header offset (use defaults if %0)
* @max_beb_per1024: maximum expected number of bad PEB per 1024 PEBs
* @padding: reserved for future, not used, has to be zeroed
*
* This data structure is used to specify MTD device UBI has to attach and the
* parameters it has to use. The number which should be assigned to the new UBI
* device is passed in @ubi_num. UBI may automatically assign the number if
* @UBI_DEV_NUM_AUTO is passed. In this case, the device number is returned in
* @ubi_num.
*
* Most applications should pass %0 in @vid_hdr_offset to make UBI use default
* offset of the VID header within physical eraseblocks. The default offset is
* the next min. I/O unit after the EC header. For example, it will be offset
* 512 in case of a 512 bytes page NAND flash with no sub-page support. Or
* it will be 512 in case of a 2KiB page NAND flash with 4 512-byte sub-pages.
*
* But in rare cases, if this optimizes things, the VID header may be placed to
* a different offset. For example, the boot-loader might do things faster if
* the VID header sits at the end of the first 2KiB NAND page with 4 sub-pages.
* As the boot-loader would not normally need to read EC headers (unless it
* needs UBI in RW mode), it might be faster to calculate ECC. This is weird
* example, but it real-life example. So, in this example, @vid_hdr_offer would
* be 2KiB-64 bytes = 1984. Note, that this position is not even 512-bytes
* aligned, which is OK, as UBI is clever enough to realize this is 4th
* sub-page of the first page and add needed padding.
*
* The @max_beb_per1024 is the maximum amount of bad PEBs UBI expects on the
* UBI device per 1024 eraseblocks. This value is often given in an other form
* in the NAND datasheet (min NVB i.e. minimal number of valid blocks). The
* maximum expected bad eraseblocks per 1024 is then:
* 1024 * (1 - MinNVB / MaxNVB)
* Which gives 20 for most NAND devices. This limit is used in order to derive
* amount of eraseblock UBI reserves for handling new bad blocks. If the device
* has more bad eraseblocks than this limit, UBI does not reserve any physical
* eraseblocks for new bad eraseblocks, but attempts to use available
* eraseblocks (if any). The accepted range is 0-768. If 0 is given, the
* default kernel value of %CONFIG_MTD_UBI_BEB_LIMIT will be used.
*/
struct ubi_attach_req {
int32_t ubi_num;
int32_t mtd_num;
int32_t vid_hdr_offset;
int16_t max_beb_per1024;
int8_t padding[10];
};
/**
* struct ubi_mkvol_req - volume description data structure used in
* volume creation requests.
* @vol_id: volume number
* @alignment: volume alignment
* @bytes: volume size in bytes
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
* @padding1: reserved for future, not used, has to be zeroed
* @name_len: volume name length
* @padding2: reserved for future, not used, has to be zeroed
* @name: volume name
*
* This structure is used by user-space programs when creating new volumes. The
* @used_bytes field is only necessary when creating static volumes.
*
* The @alignment field specifies the required alignment of the volume logical
* eraseblock. This means, that the size of logical eraseblocks will be aligned
* to this number, i.e.,
* (UBI device logical eraseblock size) mod (@alignment) = 0.
*
* To put it differently, the logical eraseblock of this volume may be slightly
* shortened in order to make it properly aligned. The alignment has to be
* multiple of the flash minimal input/output unit, or %1 to utilize the entire
* available space of logical eraseblocks.
*
* The @alignment field may be useful, for example, when one wants to maintain
* a block device on top of an UBI volume. In this case, it is desirable to fit
* an integer number of blocks in logical eraseblocks of this UBI volume. With
* alignment it is possible to update this volume using plane UBI volume image
* BLOBs, without caring about how to properly align them.
*/
struct ubi_mkvol_req {
int32_t vol_id;
int32_t alignment;
int64_t bytes;
int8_t vol_type;
int8_t padding1;
int16_t name_len;
int8_t padding2[4];
char name[UBI_MAX_VOLUME_NAME + 1];
} __attribute__((packed));
/**
* struct ubi_rsvol_req - a data structure used in volume re-size requests.
* @vol_id: ID of the volume to re-size
* @bytes: new size of the volume in bytes
*
* Re-sizing is possible for both dynamic and static volumes. But while dynamic
* volumes may be re-sized arbitrarily, static volumes cannot be made to be
* smaller than the number of bytes they bear. To arbitrarily shrink a static
* volume, it must be wiped out first (by means of volume update operation with
* zero number of bytes).
*/
struct ubi_rsvol_req {
int64_t bytes;
int32_t vol_id;
} __attribute__((packed));
/**
* struct ubi_rnvol_req - volumes re-name request.
* @count: count of volumes to re-name
* @padding1: reserved for future, not used, has to be zeroed
* @vol_id: ID of the volume to re-name
* @name_len: name length
* @padding2: reserved for future, not used, has to be zeroed
* @name: new volume name
*
* UBI allows to re-name up to %32 volumes at one go. The count of volumes to
* re-name is specified in the @count field. The ID of the volumes to re-name
* and the new names are specified in the @vol_id and @name fields.
*
* The UBI volume re-name operation is atomic, which means that should power cut
* happen, the volumes will have either old name or new name. So the possible
* use-cases of this command is atomic upgrade. Indeed, to upgrade, say, volumes
* A and B one may create temporary volumes %A1 and %B1 with the new contents,
* then atomically re-name A1->A and B1->B, in which case old %A and %B will
* be removed.
*
* If it is not desirable to remove old A and B, the re-name request has to
* contain 4 entries: A1->A, A->A1, B1->B, B->B1, in which case old A1 and B1
* become A and B, and old A and B will become A1 and B1.
*
* It is also OK to request: A1->A, A1->X, B1->B, B->Y, in which case old A1
* and B1 become A and B, and old A and B become X and Y.
*
* In other words, in case of re-naming into an existing volume name, the
* existing volume is removed, unless it is re-named as well at the same
* re-name request.
*/
struct ubi_rnvol_req {
int32_t count;
int8_t padding1[12];
struct {
int32_t vol_id;
int16_t name_len;
int8_t padding2[2];
char name[UBI_MAX_VOLUME_NAME + 1];
} ents[UBI_MAX_RNVOL];
} __attribute__((packed));
/**
* struct ubi_leb_change_req - a data structure used in atomic LEB change
* requests.
* @lnum: logical eraseblock number to change
* @bytes: how many bytes will be written to the logical eraseblock
* @dtype: pass "3" for better compatibility with old kernels
* @padding: reserved for future, not used, has to be zeroed
*
* The @dtype field used to inform UBI about what kind of data will be written
* to the LEB: long term (value 1), short term (value 2), unknown (value 3).
* UBI tried to pick a PEB with lower erase counter for short term data and a
* PEB with higher erase counter for long term data. But this was not really
* used because users usually do not know this and could easily mislead UBI. We
* removed this feature in May 2012. UBI currently just ignores the @dtype
* field. But for better compatibility with older kernels it is recommended to
* set @dtype to 3 (unknown).
*/
struct ubi_leb_change_req {
int32_t lnum;
int32_t bytes;
int8_t dtype; /* obsolete, do not use! */
int8_t padding[7];
} __attribute__((packed));
/**
* struct ubi_map_req - a data structure used in map LEB requests.
* @dtype: pass "3" for better compatibility with old kernels
* @lnum: logical eraseblock number to unmap
* @padding: reserved for future, not used, has to be zeroed
*/
struct ubi_map_req {
int32_t lnum;
int8_t dtype; /* obsolete, do not use! */
int8_t padding[3];
} __attribute__((packed));
/**
* struct ubi_set_vol_prop_req - a data structure used to set an UBI volume
* property.
* @property: property to set (%UBI_VOL_PROP_DIRECT_WRITE)
* @padding: reserved for future, not used, has to be zeroed
* @value: value to set
*/
struct ubi_set_vol_prop_req {
uint8_t property;
uint8_t padding[7];
uint64_t value;
} __attribute__((packed));
#endif /* __UBI_USER_H__ */

View File

@@ -0,0 +1,51 @@
#ifndef MTD_SWAB_H
#define MTD_SWAB_H
#include <endian.h>
#define swab16(x) \
((uint16_t)( \
(((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \
(((uint16_t)(x) & (uint16_t)0xff00U) >> 8) ))
#define swab32(x) \
((uint32_t)( \
(((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \
(((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \
(((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \
(((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) ))
#define swab64(x) \
((uint64_t)( \
(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \
(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \
(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \
(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \
(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \
(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \
(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \
(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) ))
#if __BYTE_ORDER == __BIG_ENDIAN
#define cpu_to_le16(x) ({ uint16_t _x = x; swab16(_x); })
#define cpu_to_le32(x) ({ uint32_t _x = x; swab32(_x); })
#define cpu_to_le64(x) ({ uint64_t _x = x; swab64(_x); })
#define cpu_to_be16(x) (x)
#define cpu_to_be32(x) (x)
#define cpu_to_be64(x) (x)
#else
#define cpu_to_le16(x) (x)
#define cpu_to_le32(x) (x)
#define cpu_to_le64(x) (x)
#define cpu_to_be16(x) ({ uint16_t _x = x; swab16(_x); })
#define cpu_to_be32(x) ({ uint32_t _x = x; swab32(_x); })
#define cpu_to_be64(x) ({ uint64_t _x = x; swab64(_x); })
#endif
#define le16_to_cpu(x) cpu_to_le16(x)
#define be16_to_cpu(x) cpu_to_be16(x)
#define le32_to_cpu(x) cpu_to_le32(x)
#define be32_to_cpu(x) cpu_to_be32(x)
#define le64_to_cpu(x) cpu_to_le64(x)
#define be64_to_cpu(x) cpu_to_be64(x)
#endif

View File

@@ -0,0 +1,106 @@
/*
* memory wrappers
*
* Copyright (c) Artem Bityutskiy, 2007, 2008
* Copyright 2001, 2002 Red Hat, Inc.
* 2001 David A. Schleef <ds@lineo.com>
* 2002 Axis Communications AB
* 2001, 2002 Erik Andersen <andersen@codepoet.org>
* 2004 University of Szeged, Hungary
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MTD_UTILS_XALLOC_H__
#define __MTD_UTILS_XALLOC_H__
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
/*
* Mark these functions as unused so that gcc does not emit warnings
* when people include this header but don't use every function.
*/
__attribute__((unused))
static void *xmalloc(size_t size)
{
void *ptr = malloc(size);
if (ptr == NULL && size != 0)
sys_errmsg("out of memory");
return ptr;
}
__attribute__((unused))
static void *xcalloc(size_t nmemb, size_t size)
{
void *ptr = calloc(nmemb, size);
if (ptr == NULL && nmemb != 0 && size != 0)
sys_errmsg("out of memory");
return ptr;
}
__attribute__((unused))
static void *xzalloc(size_t size)
{
return xcalloc(1, size);
}
__attribute__((unused))
static void *xrealloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (ptr == NULL && size != 0)
sys_errmsg("out of memory");
return ptr;
}
__attribute__((unused))
static char *xstrdup(const char *s)
{
char *t;
if (s == NULL)
return NULL;
t = strdup(s);
if (t == NULL)
sys_errmsg("out of memory");
return t;
}
#ifdef _GNU_SOURCE
__attribute__((unused))
static int xasprintf(char **strp, const char *fmt, ...)
{
int cnt;
va_list ap;
va_start(ap, fmt);
cnt = vasprintf(strp, fmt, ap);
va_end(ap);
if (cnt == -1)
sys_errmsg("out of memory");
return cnt;
}
#endif
#endif /* !__MTD_UTILS_XALLOC_H__ */

View File

@@ -0,0 +1,104 @@
/*
* COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
* code or tables extracted from it, as desired without restriction.
*
* First, the polynomial itself and its table of feedback terms. The
* polynomial is
* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0
*
* Note that we take it "backwards" and put the highest-order term in
* the lowest-order bit. The X^32 term is "implied"; the LSB is the
* X^31 term, etc. The X^0 term (usually shown as "+1") results in
* the MSB being 1
*
* Note that the usual hardware shift register implementation, which
* is what we're using (we're merely optimizing it by doing eight-bit
* chunks at a time) shifts bits into the lowest-order term. In our
* implementation, that means shifting towards the right. Why do we
* do it this way? Because the calculated CRC must be transmitted in
* order from highest-order term to lowest-order term. UARTs transmit
* characters in order from LSB to MSB. By storing the CRC this way
* we hand it to the UART in the order low-byte to high-byte; the UART
* sends each low-bit to hight-bit; and the result is transmission bit
* by bit from highest- to lowest-order term without requiring any bit
* shuffling on our part. Reception works similarly
*
* The feedback terms table consists of 256, 32-bit entries. Notes
*
* The table can be generated at runtime if desired; code to do so
* is shown later. It might not be obvious, but the feedback
* terms simply represent the results of eight shift/xor opera
* tions for all combinations of data and CRC register values
*
* The values must be right-shifted by eight bits by the "updcrc
* logic; the shift must be unsigned (bring in zeroes). On some
* hardware you could probably optimize the shift in assembler by
* using byte-swap instructions
* polynomial $edb88320
*/
#include <stdint.h>
static const uint32_t crc32_table[256] = {
0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
0x2d02ef8dL
};
uint32_t mtd_crc32(uint32_t val, const void *ss, int len)
{
const unsigned char *s = (unsigned char *)ss;
while (--len >= 0)
val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8);
return val;
}

View File

@@ -0,0 +1,903 @@
/*
* fec.c -- forward error correction based on Vandermonde matrices
* 980624
* (C) 1997-98 Luigi Rizzo (luigi@iet.unipi.it)
*
* Portions derived from code by Phil Karn (karn@ka9q.ampr.org),
* Robert Morelos-Zaragoza (robert@spectra.eng.hawaii.edu) and Hari
* Thirumoorthy (harit@spectra.eng.hawaii.edu), Aug 1995
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*/
/*
* The following parameter defines how many bits are used for
* field elements. The code supports any value from 2 to 16
* but fastest operation is achieved with 8 bit elements
* This is the only parameter you may want to change.
*/
#ifndef GF_BITS
#define GF_BITS 8 /* code over GF(2**GF_BITS) - change to suit */
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* stuff used for testing purposes only
*/
#ifdef TEST
#define DEB(x)
#define DDB(x) x
#define DEBUG 0 /* minimal debugging */
#ifdef MSDOS
#include <time.h>
struct timeval {
unsigned long ticks;
};
#define gettimeofday(x, dummy) { (x)->ticks = clock() ; }
#define DIFF_T(a,b) (1+ 1000000*(a.ticks - b.ticks) / CLOCKS_PER_SEC )
typedef unsigned long u_long ;
typedef unsigned short u_short ;
#else /* typically, unix systems */
#include <sys/time.h>
#define DIFF_T(a,b) \
(1+ 1000000*(a.tv_sec - b.tv_sec) + (a.tv_usec - b.tv_usec) )
#endif
#define TICK(t) \
{struct timeval x ; \
gettimeofday(&x, NULL) ; \
t = x.tv_usec + 1000000* (x.tv_sec & 0xff ) ; \
}
#define TOCK(t) \
{ u_long t1 ; TICK(t1) ; \
if (t1 < t) t = 256000000 + t1 - t ; \
else t = t1 - t ; \
if (t == 0) t = 1 ;}
u_long ticks[10]; /* vars for timekeeping */
#else
#define DEB(x)
#define DDB(x)
#define TICK(x)
#define TOCK(x)
#endif /* TEST */
/*
* You should not need to change anything beyond this point.
* The first part of the file implements linear algebra in GF.
*
* gf is the type used to store an element of the Galois Field.
* Must constain at least GF_BITS bits.
*
* Note: unsigned char will work up to GF(256) but int seems to run
* faster on the Pentium. We use int whenever have to deal with an
* index, since they are generally faster.
*/
#if (GF_BITS < 2 && GF_BITS >16)
#error "GF_BITS must be 2 .. 16"
#endif
#if (GF_BITS <= 8)
typedef unsigned char gf;
#else
typedef unsigned short gf;
#endif
#define GF_SIZE ((1 << GF_BITS) - 1) /* powers of \alpha */
/*
* Primitive polynomials - see Lin & Costello, Appendix A,
* and Lee & Messerschmitt, p. 453.
*/
static const char *allPp[] = { /* GF_BITS polynomial */
NULL, /* 0 no code */
NULL, /* 1 no code */
"111", /* 2 1+x+x^2 */
"1101", /* 3 1+x+x^3 */
"11001", /* 4 1+x+x^4 */
"101001", /* 5 1+x^2+x^5 */
"1100001", /* 6 1+x+x^6 */
"10010001", /* 7 1 + x^3 + x^7 */
"101110001", /* 8 1+x^2+x^3+x^4+x^8 */
"1000100001", /* 9 1+x^4+x^9 */
"10010000001", /* 10 1+x^3+x^10 */
"101000000001", /* 11 1+x^2+x^11 */
"1100101000001", /* 12 1+x+x^4+x^6+x^12 */
"11011000000001", /* 13 1+x+x^3+x^4+x^13 */
"110000100010001", /* 14 1+x+x^6+x^10+x^14 */
"1100000000000001", /* 15 1+x+x^15 */
"11010000000010001" /* 16 1+x+x^3+x^12+x^16 */
};
/*
* To speed up computations, we have tables for logarithm, exponent
* and inverse of a number. If GF_BITS <= 8, we use a table for
* multiplication as well (it takes 64K, no big deal even on a PDA,
* especially because it can be pre-initialized an put into a ROM!),
* otherwhise we use a table of logarithms.
* In any case the macro gf_mul(x,y) takes care of multiplications.
*/
static gf gf_exp[2*GF_SIZE]; /* index->poly form conversion table */
static int gf_log[GF_SIZE + 1]; /* Poly->index form conversion table */
static gf inverse[GF_SIZE+1]; /* inverse of field elem. */
/* inv[\alpha**i]=\alpha**(GF_SIZE-i-1) */
/*
* modnn(x) computes x % GF_SIZE, where GF_SIZE is 2**GF_BITS - 1,
* without a slow divide.
*/
static inline gf
modnn(int x)
{
while (x >= GF_SIZE) {
x -= GF_SIZE;
x = (x >> GF_BITS) + (x & GF_SIZE);
}
return x;
}
#define SWAP(a,b,t) {t tmp; tmp=a; a=b; b=tmp;}
/*
* gf_mul(x,y) multiplies two numbers. If GF_BITS<=8, it is much
* faster to use a multiplication table.
*
* USE_GF_MULC, GF_MULC0(c) and GF_ADDMULC(x) can be used when multiplying
* many numbers by the same constant. In this case the first
* call sets the constant, and others perform the multiplications.
* A value related to the multiplication is held in a local variable
* declared with USE_GF_MULC . See usage in addmul1().
*/
#if (GF_BITS <= 8)
static gf gf_mul_table[GF_SIZE + 1][GF_SIZE + 1];
#define gf_mul(x,y) gf_mul_table[x][y]
#define USE_GF_MULC register gf * __gf_mulc_
#define GF_MULC0(c) __gf_mulc_ = gf_mul_table[c]
#define GF_ADDMULC(dst, x) dst ^= __gf_mulc_[x]
static void
init_mul_table(void)
{
int i, j;
for (i=0; i< GF_SIZE+1; i++)
for (j=0; j< GF_SIZE+1; j++)
gf_mul_table[i][j] = gf_exp[modnn(gf_log[i] + gf_log[j]) ] ;
for (j=0; j< GF_SIZE+1; j++)
gf_mul_table[0][j] = gf_mul_table[j][0] = 0;
}
#else /* GF_BITS > 8 */
static inline gf
gf_mul(x,y)
{
if ( (x) == 0 || (y)==0 ) return 0;
return gf_exp[gf_log[x] + gf_log[y] ] ;
}
#define init_mul_table()
#define USE_GF_MULC register gf * __gf_mulc_
#define GF_MULC0(c) __gf_mulc_ = &gf_exp[ gf_log[c] ]
#define GF_ADDMULC(dst, x) { if (x) dst ^= __gf_mulc_[ gf_log[x] ] ; }
#endif
/*
* Generate GF(2**m) from the irreducible polynomial p(X) in p[0]..p[m]
* Lookup tables:
* index->polynomial form gf_exp[] contains j= \alpha^i;
* polynomial form -> index form gf_log[ j = \alpha^i ] = i
* \alpha=x is the primitive element of GF(2^m)
*
* For efficiency, gf_exp[] has size 2*GF_SIZE, so that a simple
* multiplication of two numbers can be resolved without calling modnn
*/
/*
* i use malloc so many times, it is easier to put checks all in
* one place.
*/
static void *
my_malloc(int sz, const char *err_string)
{
void *p = malloc( sz );
if (p == NULL) {
fprintf(stderr, "-- malloc failure allocating %s\n", err_string);
exit(1) ;
}
return p ;
}
#define NEW_GF_MATRIX(rows, cols) \
(gf *)my_malloc(rows * cols * sizeof(gf), " ## __LINE__ ## " )
/*
* initialize the data structures used for computations in GF.
*/
static void
generate_gf(void)
{
int i;
gf mask;
const char *Pp = allPp[GF_BITS] ;
mask = 1; /* x ** 0 = 1 */
gf_exp[GF_BITS] = 0; /* will be updated at the end of the 1st loop */
/*
* first, generate the (polynomial representation of) powers of \alpha,
* which are stored in gf_exp[i] = \alpha ** i .
* At the same time build gf_log[gf_exp[i]] = i .
* The first GF_BITS powers are simply bits shifted to the left.
*/
for (i = 0; i < GF_BITS; i++, mask <<= 1 ) {
gf_exp[i] = mask;
gf_log[gf_exp[i]] = i;
/*
* If Pp[i] == 1 then \alpha ** i occurs in poly-repr
* gf_exp[GF_BITS] = \alpha ** GF_BITS
*/
if ( Pp[i] == '1' )
gf_exp[GF_BITS] ^= mask;
}
/*
* now gf_exp[GF_BITS] = \alpha ** GF_BITS is complete, so can als
* compute its inverse.
*/
gf_log[gf_exp[GF_BITS]] = GF_BITS;
/*
* Poly-repr of \alpha ** (i+1) is given by poly-repr of
* \alpha ** i shifted left one-bit and accounting for any
* \alpha ** GF_BITS term that may occur when poly-repr of
* \alpha ** i is shifted.
*/
mask = 1 << (GF_BITS - 1 ) ;
for (i = GF_BITS + 1; i < GF_SIZE; i++) {
if (gf_exp[i - 1] >= mask)
gf_exp[i] = gf_exp[GF_BITS] ^ ((gf_exp[i - 1] ^ mask) << 1);
else
gf_exp[i] = gf_exp[i - 1] << 1;
gf_log[gf_exp[i]] = i;
}
/*
* log(0) is not defined, so use a special value
*/
gf_log[0] = GF_SIZE ;
/* set the extended gf_exp values for fast multiply */
for (i = 0 ; i < GF_SIZE ; i++)
gf_exp[i + GF_SIZE] = gf_exp[i] ;
/*
* again special cases. 0 has no inverse. This used to
* be initialized to GF_SIZE, but it should make no difference
* since noone is supposed to read from here.
*/
inverse[0] = 0 ;
inverse[1] = 1;
for (i=2; i<=GF_SIZE; i++)
inverse[i] = gf_exp[GF_SIZE-gf_log[i]];
}
/*
* Various linear algebra operations that i use often.
*/
/*
* addmul() computes dst[] = dst[] + c * src[]
* This is used often, so better optimize it! Currently the loop is
* unrolled 16 times, a good value for 486 and pentium-class machines.
* The case c=0 is also optimized, whereas c=1 is not. These
* calls are unfrequent in my typical apps so I did not bother.
*
* Note that gcc on
*/
#define addmul(dst, src, c, sz) \
if (c != 0) addmul1(dst, src, c, sz)
#define UNROLL 16 /* 1, 4, 8, 16 */
static void
addmul1(gf *dst1, gf *src1, gf c, int sz)
{
USE_GF_MULC ;
register gf *dst = dst1, *src = src1 ;
gf *lim = &dst[sz - UNROLL + 1] ;
GF_MULC0(c) ;
#if (UNROLL > 1) /* unrolling by 8/16 is quite effective on the pentium */
for (; dst < lim ; dst += UNROLL, src += UNROLL ) {
GF_ADDMULC( dst[0] , src[0] );
GF_ADDMULC( dst[1] , src[1] );
GF_ADDMULC( dst[2] , src[2] );
GF_ADDMULC( dst[3] , src[3] );
#if (UNROLL > 4)
GF_ADDMULC( dst[4] , src[4] );
GF_ADDMULC( dst[5] , src[5] );
GF_ADDMULC( dst[6] , src[6] );
GF_ADDMULC( dst[7] , src[7] );
#endif
#if (UNROLL > 8)
GF_ADDMULC( dst[8] , src[8] );
GF_ADDMULC( dst[9] , src[9] );
GF_ADDMULC( dst[10] , src[10] );
GF_ADDMULC( dst[11] , src[11] );
GF_ADDMULC( dst[12] , src[12] );
GF_ADDMULC( dst[13] , src[13] );
GF_ADDMULC( dst[14] , src[14] );
GF_ADDMULC( dst[15] , src[15] );
#endif
}
#endif
lim += UNROLL - 1 ;
for (; dst < lim; dst++, src++ ) /* final components */
GF_ADDMULC( *dst , *src );
}
/*
* computes C = AB where A is n*k, B is k*m, C is n*m
*/
static void
matmul(gf *a, gf *b, gf *c, int n, int k, int m)
{
int row, col, i ;
for (row = 0; row < n ; row++) {
for (col = 0; col < m ; col++) {
gf *pa = &a[ row * k ];
gf *pb = &b[ col ];
gf acc = 0 ;
for (i = 0; i < k ; i++, pa++, pb += m )
acc ^= gf_mul( *pa, *pb ) ;
c[ row * m + col ] = acc ;
}
}
}
#ifdef DEBUG
/*
* returns 1 if the square matrix is identiy
* (only for test)
*/
static int
is_identity(gf *m, int k)
{
int row, col ;
for (row=0; row<k; row++)
for (col=0; col<k; col++)
if ( (row==col && *m != 1) ||
(row!=col && *m != 0) )
return 0 ;
else
m++ ;
return 1 ;
}
#endif /* debug */
/*
* invert_mat() takes a matrix and produces its inverse
* k is the size of the matrix.
* (Gauss-Jordan, adapted from Numerical Recipes in C)
* Return non-zero if singular.
*/
DEB( int pivloops=0; int pivswaps=0 ; /* diagnostic */)
static int
invert_mat(gf *src, int k)
{
gf c, *p ;
int irow, icol, row, col, i, ix ;
int error = 1 ;
int *indxc = (int*)my_malloc(k*sizeof(int), "indxc");
int *indxr = (int*)my_malloc(k*sizeof(int), "indxr");
int *ipiv = (int*)my_malloc(k*sizeof(int), "ipiv");
gf *id_row = NEW_GF_MATRIX(1, k);
gf *temp_row = NEW_GF_MATRIX(1, k);
memset(id_row, '\0', k*sizeof(gf));
DEB( pivloops=0; pivswaps=0 ; /* diagnostic */ )
/*
* ipiv marks elements already used as pivots.
*/
for (i = 0; i < k ; i++)
ipiv[i] = 0 ;
for (col = 0; col < k ; col++) {
gf *pivot_row ;
/*
* Zeroing column 'col', look for a non-zero element.
* First try on the diagonal, if it fails, look elsewhere.
*/
irow = icol = -1 ;
if (ipiv[col] != 1 && src[col*k + col] != 0) {
irow = col ;
icol = col ;
goto found_piv ;
}
for (row = 0 ; row < k ; row++) {
if (ipiv[row] != 1) {
for (ix = 0 ; ix < k ; ix++) {
DEB( pivloops++ ; )
if (ipiv[ix] == 0) {
if (src[row*k + ix] != 0) {
irow = row ;
icol = ix ;
goto found_piv ;
}
} else if (ipiv[ix] > 1) {
fprintf(stderr, "singular matrix\n");
goto fail ;
}
}
}
}
if (icol == -1) {
fprintf(stderr, "XXX pivot not found!\n");
goto fail ;
}
found_piv:
++(ipiv[icol]) ;
/*
* swap rows irow and icol, so afterwards the diagonal
* element will be correct. Rarely done, not worth
* optimizing.
*/
if (irow != icol) {
for (ix = 0 ; ix < k ; ix++ ) {
SWAP( src[irow*k + ix], src[icol*k + ix], gf) ;
}
}
indxr[col] = irow ;
indxc[col] = icol ;
pivot_row = &src[icol*k] ;
c = pivot_row[icol] ;
if (c == 0) {
fprintf(stderr, "singular matrix 2\n");
goto fail ;
}
if (c != 1 ) { /* otherwhise this is a NOP */
/*
* this is done often , but optimizing is not so
* fruitful, at least in the obvious ways (unrolling)
*/
DEB( pivswaps++ ; )
c = inverse[ c ] ;
pivot_row[icol] = 1 ;
for (ix = 0 ; ix < k ; ix++ )
pivot_row[ix] = gf_mul(c, pivot_row[ix] );
}
/*
* from all rows, remove multiples of the selected row
* to zero the relevant entry (in fact, the entry is not zero
* because we know it must be zero).
* (Here, if we know that the pivot_row is the identity,
* we can optimize the addmul).
*/
id_row[icol] = 1;
if (memcmp(pivot_row, id_row, k*sizeof(gf)) != 0) {
for (p = src, ix = 0 ; ix < k ; ix++, p += k ) {
if (ix != icol) {
c = p[icol] ;
p[icol] = 0 ;
addmul(p, pivot_row, c, k );
}
}
}
id_row[icol] = 0;
} /* done all columns */
for (col = k-1 ; col >= 0 ; col-- ) {
if (indxr[col] <0 || indxr[col] >= k)
fprintf(stderr, "AARGH, indxr[col] %d\n", indxr[col]);
else if (indxc[col] <0 || indxc[col] >= k)
fprintf(stderr, "AARGH, indxc[col] %d\n", indxc[col]);
else
if (indxr[col] != indxc[col] ) {
for (row = 0 ; row < k ; row++ ) {
SWAP( src[row*k + indxr[col]], src[row*k + indxc[col]], gf) ;
}
}
}
error = 0 ;
fail:
free(indxc);
free(indxr);
free(ipiv);
free(id_row);
free(temp_row);
return error ;
}
/*
* fast code for inverting a vandermonde matrix.
* XXX NOTE: It assumes that the matrix
* is not singular and _IS_ a vandermonde matrix. Only uses
* the second column of the matrix, containing the p_i's.
*
* Algorithm borrowed from "Numerical recipes in C" -- sec.2.8, but
* largely revised for my purposes.
* p = coefficients of the matrix (p_i)
* q = values of the polynomial (known)
*/
int
invert_vdm(gf *src, int k)
{
int i, j, row, col ;
gf *b, *c, *p;
gf t, xx ;
if (k == 1) /* degenerate case, matrix must be p^0 = 1 */
return 0 ;
/*
* c holds the coefficient of P(x) = Prod (x - p_i), i=0..k-1
* b holds the coefficient for the matrix inversion
*/
c = NEW_GF_MATRIX(1, k);
b = NEW_GF_MATRIX(1, k);
p = NEW_GF_MATRIX(1, k);
for ( j=1, i = 0 ; i < k ; i++, j+=k ) {
c[i] = 0 ;
p[i] = src[j] ; /* p[i] */
}
/*
* construct coeffs. recursively. We know c[k] = 1 (implicit)
* and start P_0 = x - p_0, then at each stage multiply by
* x - p_i generating P_i = x P_{i-1} - p_i P_{i-1}
* After k steps we are done.
*/
c[k-1] = p[0] ; /* really -p(0), but x = -x in GF(2^m) */
for (i = 1 ; i < k ; i++ ) {
gf p_i = p[i] ; /* see above comment */
for (j = k-1 - ( i - 1 ) ; j < k-1 ; j++ )
c[j] ^= gf_mul( p_i, c[j+1] ) ;
c[k-1] ^= p_i ;
}
for (row = 0 ; row < k ; row++ ) {
/*
* synthetic division etc.
*/
xx = p[row] ;
t = 1 ;
b[k-1] = 1 ; /* this is in fact c[k] */
for (i = k-2 ; i >= 0 ; i-- ) {
b[i] = c[i+1] ^ gf_mul(xx, b[i+1]) ;
t = gf_mul(xx, t) ^ b[i] ;
}
for (col = 0 ; col < k ; col++ )
src[col*k + row] = gf_mul(inverse[t], b[col] );
}
free(c) ;
free(b) ;
free(p) ;
return 0 ;
}
static int fec_initialized = 0 ;
static void
init_fec(void)
{
TICK(ticks[0]);
generate_gf();
TOCK(ticks[0]);
DDB(fprintf(stderr, "generate_gf took %ldus\n", ticks[0]);)
TICK(ticks[0]);
init_mul_table();
TOCK(ticks[0]);
DDB(fprintf(stderr, "init_mul_table took %ldus\n", ticks[0]);)
fec_initialized = 1 ;
}
/*
* This section contains the proper FEC encoding/decoding routines.
* The encoding matrix is computed starting with a Vandermonde matrix,
* and then transforming it into a systematic matrix.
*/
#define FEC_MAGIC 0xFECC0DEC
struct fec_parms {
u_long magic ;
int k, n ; /* parameters of the code */
gf *enc_matrix ;
} ;
#define COMP_FEC_MAGIC(fec) \
(((FEC_MAGIC ^ (fec)->k) ^ (fec)->n) ^ (unsigned long)((fec)->enc_matrix))
void
fec_free(struct fec_parms *p)
{
if (p==NULL || p->magic != COMP_FEC_MAGIC(p)) {
fprintf(stderr, "bad parameters to fec_free\n");
return ;
}
free(p->enc_matrix);
free(p);
}
/*
* create a new encoder, returning a descriptor. This contains k,n and
* the encoding matrix.
*/
struct fec_parms *
fec_new(int k, int n)
{
int row, col ;
gf *p, *tmp_m ;
struct fec_parms *retval ;
if (fec_initialized == 0)
init_fec();
if (k > GF_SIZE + 1 || n > GF_SIZE + 1 || k > n ) {
fprintf(stderr, "Invalid parameters k %d n %d GF_SIZE %d\n",
k, n, GF_SIZE );
return NULL ;
}
retval = reinterpret_cast<fec_parms*>(my_malloc(sizeof(struct fec_parms), "new_code"));
retval->k = k ;
retval->n = n ;
retval->enc_matrix = NEW_GF_MATRIX(n, k);
retval->magic = COMP_FEC_MAGIC(retval);
tmp_m = NEW_GF_MATRIX(n, k);
/*
* fill the matrix with powers of field elements, starting from 0.
* The first row is special, cannot be computed with exp. table.
*/
tmp_m[0] = 1 ;
for (col = 1; col < k ; col++)
tmp_m[col] = 0 ;
for (p = tmp_m + k, row = 0; row < n-1 ; row++, p += k) {
for ( col = 0 ; col < k ; col ++ )
p[col] = gf_exp[modnn(row*col)];
}
/*
* quick code to build systematic matrix: invert the top
* k*k vandermonde matrix, multiply right the bottom n-k rows
* by the inverse, and construct the identity matrix at the top.
*/
TICK(ticks[3]);
invert_vdm(tmp_m, k); /* much faster than invert_mat */
matmul(tmp_m + k*k, tmp_m, retval->enc_matrix + k*k, n - k, k, k);
/*
* the upper matrix is I so do not bother with a slow multiply
*/
memset(retval->enc_matrix, '\0', k*k*sizeof(gf) );
for (p = retval->enc_matrix, col = 0 ; col < k ; col++, p += k+1 )
*p = 1 ;
free(tmp_m);
TOCK(ticks[3]);
DDB(fprintf(stderr, "--- %ld us to build encoding matrix\n",
ticks[3]);)
DEB(pr_matrix(retval->enc_matrix, n, k, "encoding_matrix");)
return retval ;
}
/*
* fec_encode accepts as input pointers to n data packets of size sz,
* and produces as output a packet pointed to by fec, computed
* with index "index".
*/
void
fec_encode(struct fec_parms *code, gf *src[], gf *fec, int index, int sz)
{
int k = code->k ;
if (GF_BITS > 8)
sz /= 2 ;
if (index < k)
memcpy(fec, src[index], sz*sizeof(gf) ) ;
else if (index < code->n) {
gf* p = &(code->enc_matrix[index*k] );
memset(fec, '\0', sz*sizeof(gf));
for (int i = 0; i < k ; i++)
addmul(fec, src[i], p[i], sz ) ;
} else
fprintf(stderr, "Invalid index %d (max %d)\n",
index, code->n - 1 );
}
void fec_encode_linear(struct fec_parms *code, gf *src, gf *fec, int index, int sz)
{
int k = code->k ;
if (GF_BITS > 8)
sz /= 2 ;
if (index < k)
memcpy(fec, src + (index * sz), sz*sizeof(gf) ) ;
else if (index < code->n) {
gf* p = &(code->enc_matrix[index*k] );
memset(fec, '\0', sz*sizeof(gf));
for (int i = 0; i < k ; i++)
addmul(fec, src + (i * sz), p[i], sz ) ;
} else
fprintf(stderr, "Invalid index %d (max %d)\n",
index, code->n - 1 );
}
/*
* shuffle move src packets in their position
*/
static int
shuffle(gf *pkt[], int index[], int k)
{
int i;
for ( i = 0 ; i < k ; ) {
if (index[i] >= k || index[i] == i)
i++ ;
else {
/*
* put pkt in the right position (first check for conflicts).
*/
int c = index[i] ;
if (index[c] == c) {
DEB(fprintf(stderr, "\nshuffle, error at %d\n", i);)
return 1 ;
}
SWAP(index[i], index[c], int) ;
SWAP(pkt[i], pkt[c], gf *) ;
}
}
DEB( /* just test that it works... */
for ( i = 0 ; i < k ; i++ ) {
if (index[i] < k && index[i] != i) {
fprintf(stderr, "shuffle: after\n");
for (i=0; i<k ; i++) fprintf(stderr, "%3d ", index[i]);
fprintf(stderr, "\n");
return 1 ;
}
}
)
return 0 ;
}
/*
* build_decode_matrix constructs the encoding matrix given the
* indexes. The matrix must be already allocated as
* a vector of k*k elements, in row-major order
*/
static gf *
build_decode_matrix(struct fec_parms *code, int index[])
{
int i , k = code->k ;
gf *p, *matrix = NEW_GF_MATRIX(k, k);
TICK(ticks[9]);
for (i = 0, p = matrix ; i < k ; i++, p += k ) {
#if 1 /* this is simply an optimization, not very useful indeed */
if (index[i] < k) {
memset(p, '\0', k*sizeof(gf) );
p[i] = 1 ;
} else
#endif
if (index[i] < code->n )
memcpy(p, &(code->enc_matrix[index[i]*k]), k*sizeof(gf) );
else {
fprintf(stderr, "decode: invalid index %d (max %d)\n",
index[i], code->n - 1 );
free(matrix) ;
return NULL ;
}
}
TICK(ticks[9]);
if (invert_mat(matrix, k)) {
free(matrix);
matrix = NULL ;
}
TOCK(ticks[9]);
return matrix ;
}
/*
* fec_decode receives as input a vector of packets, the indexes of
* packets, and produces the correct vector as output.
*
* Input:
* code: pointer to code descriptor
* pkt: pointers to received packets. They are modified
* to store the output packets (in place)
* index: pointer to packet indexes (modified)
* sz: size of each packet
*/
int
fec_decode(struct fec_parms *code, gf *pkt[], int index[], int sz)
{
gf *m_dec ;
gf **new_pkt ;
int row, col , k = code->k ;
if (GF_BITS > 8)
sz /= 2 ;
if (shuffle(pkt, index, k)) /* error if true */
return 1 ;
m_dec = build_decode_matrix(code, index);
if (m_dec == NULL)
return 1 ; /* error */
/*
* do the actual decoding
*/
new_pkt = (gf**)my_malloc (k * sizeof (gf * ), "new pkt pointers" );
for (row = 0 ; row < k ; row++ ) {
if (index[row] >= k) {
new_pkt[row] = (gf*)my_malloc (sz * sizeof (gf), "new pkt buffer" );
memset(new_pkt[row], '\0', sz * sizeof(gf) ) ;
for (col = 0 ; col < k ; col++ )
addmul(new_pkt[row], pkt[col], m_dec[row*k + col], sz) ;
}
}
/*
* move pkts to their final destination
*/
for (row = 0 ; row < k ; row++ ) {
if (index[row] >= k) {
memcpy(pkt[row], new_pkt[row], sz*sizeof(gf));
free(new_pkt[row]);
}
}
free(new_pkt);
free(m_dec);
return 0;
}
/*********** end of FEC code -- beginning of test code ************/
#if (TEST || DEBUG)
void
test_gf(void)
{
int i ;
/*
* test gf tables. Sufficiently tested...
*/
for (i=0; i<= GF_SIZE; i++) {
if (gf_exp[gf_log[i]] != i)
fprintf(stderr, "bad exp/log i %d log %d exp(log) %d\n",
i, gf_log[i], gf_exp[gf_log[i]]);
if (i != 0 && gf_mul(i, inverse[i]) != 1)
fprintf(stderr, "bad mul/inv i %d inv %d i*inv(i) %d\n",
i, inverse[i], gf_mul(i, inverse[i]) );
if (gf_mul(0,i) != 0)
fprintf(stderr, "bad mul table 0,%d\n",i);
if (gf_mul(i,0) != 0)
fprintf(stderr, "bad mul table %d,0\n",i);
}
}
#endif /* TEST */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,107 @@
/*
* Copyright (c) International Business Machines Corp., 2006
* Copyright (C) 2009 Nokia Corporation
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author: Artem Bityutskiy
*
* MTD library.
*/
#ifndef __LIBMTD_INT_H__
#define __LIBMTD_INT_H__
#ifdef __cplusplus
extern "C" {
#endif
#define PROGRAM_NAME "libmtd"
#define SYSFS_MTD "class/mtd"
#define MTD_NAME_PATT "mtd%d"
#define MTD_DEV "dev"
#define MTD_NAME "name"
#define MTD_TYPE "type"
#define MTD_EB_SIZE "erasesize"
#define MTD_SIZE "size"
#define MTD_MIN_IO_SIZE "writesize"
#define MTD_SUBPAGE_SIZE "subpagesize"
#define MTD_OOB_SIZE "oobsize"
#define MTD_REGION_CNT "numeraseregions"
#define MTD_FLAGS "flags"
#define OFFS64_IOCTLS_UNKNOWN 0
#define OFFS64_IOCTLS_NOT_SUPPORTED 1
#define OFFS64_IOCTLS_SUPPORTED 2
/**
* libmtd - MTD library description data structure.
* @sysfs_mtd: MTD directory in sysfs
* @mtd: MTD device sysfs directory pattern
* @mtd_dev: MTD device major/minor numbers file pattern
* @mtd_name: MTD device name file pattern
* @mtd_type: MTD device type file pattern
* @mtd_eb_size: MTD device eraseblock size file pattern
* @mtd_size: MTD device size file pattern
* @mtd_min_io_size: minimum I/O unit size file pattern
* @mtd_subpage_size: sub-page size file pattern
* @mtd_oob_size: MTD device OOB size file pattern
* @mtd_region_cnt: count of additional erase regions file pattern
* @mtd_flags: MTD device flags file pattern
* @sysfs_supported: non-zero if sysfs is supported by MTD
* @offs64_ioctls: %OFFS64_IOCTLS_SUPPORTED if 64-bit %MEMERASE64,
* %MEMREADOOB64, %MEMWRITEOOB64 MTD device ioctls are
* supported, %OFFS64_IOCTLS_NOT_SUPPORTED if not, and
* %OFFS64_IOCTLS_UNKNOWN if it is not known yet;
*
* Note, we cannot find out whether 64-bit ioctls are supported by MTD when we
* are initializing the library, because this requires an MTD device node.
* Indeed, we have to actually call the ioctl and check for %ENOTTY to find
* out whether it is supported or not.
*
* Thus, we leave %offs64_ioctls uninitialized in 'libmtd_open()', and
* initialize it later, when corresponding libmtd function is used, and when
* we actually have a device node and can invoke an ioctl command on it.
*/
struct libmtd
{
char *sysfs_mtd;
char *mtd;
char *mtd_dev;
char *mtd_name;
char *mtd_type;
char *mtd_eb_size;
char *mtd_size;
char *mtd_min_io_size;
char *mtd_subpage_size;
char *mtd_oob_size;
char *mtd_region_cnt;
char *mtd_flags;
unsigned int sysfs_supported:1;
unsigned int offs64_ioctls:2;
};
int legacy_libmtd_open(void);
int legacy_dev_present(int mtd_num);
int legacy_mtd_get_info(struct mtd_info *info);
int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd);
int legacy_get_dev_info1(int dev_num, struct mtd_dev_info *mtd);
#ifdef __cplusplus
}
#endif
#endif /* !__LIBMTD_INT_H__ */

View File

@@ -0,0 +1,379 @@
/*
* Copyright (C) 2009 Nokia Corporation
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Author: Artem Bityutskiy
*
* This file is part of the MTD library. Implements pre-2.6.30 kernels support,
* where MTD did not have sysfs interface. The main limitation of the old
* kernels was that the sub-page size was not exported to user-space, so it was
* not possible to get sub-page size.
*/
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
#include <libmtd.h>
#include "libmtd_int.h"
#include "common.h"
#define MTD_PROC_FILE "/proc/mtd"
#define MTD_DEV_PATT "/dev/mtd%d"
#define MTD_DEV_MAJOR 90
#define PROC_MTD_FIRST "dev: size erasesize name\n"
#define PROC_MTD_FIRST_LEN (sizeof(PROC_MTD_FIRST) - 1)
#define PROC_MTD_MAX_LEN 4096
#define PROC_MTD_PATT "mtd%d: %llx %x"
/**
* struct proc_parse_info - /proc/mtd parsing information.
* @mtd_num: MTD device number
* @size: device size
* @eb_size: eraseblock size
* @name: device name
* @buf: contents of /proc/mtd
* @data_size: how much data was read into @buf
* @pos: next string in @buf to parse
*/
struct proc_parse_info
{
int mtd_num;
long long size;
char name[MTD_NAME_MAX + 1];
int eb_size;
char *buf;
int data_size;
char *next;
};
static int proc_parse_start(struct proc_parse_info *pi)
{
int fd, ret;
fd = open(MTD_PROC_FILE, O_RDONLY);
if (fd == -1)
return -1;
pi->buf = (char*)xmalloc(PROC_MTD_MAX_LEN);
ret = read(fd, pi->buf, PROC_MTD_MAX_LEN);
if (ret == -1) {
sys_errmsg("cannot read \"%s\"", MTD_PROC_FILE);
goto out_free;
}
if (ret < (int)PROC_MTD_FIRST_LEN ||
memcmp(pi->buf, PROC_MTD_FIRST, PROC_MTD_FIRST_LEN)) {
errmsg("\"%s\" does not start with \"%s\"", MTD_PROC_FILE,
PROC_MTD_FIRST);
goto out_free;
}
pi->data_size = ret;
pi->next = pi->buf + PROC_MTD_FIRST_LEN;
close(fd);
return 0;
out_free:
free(pi->buf);
close(fd);
return -1;
}
static int proc_parse_next(struct proc_parse_info *pi)
{
int ret, len, pos = pi->next - pi->buf;
char *p, *p1;
if (pos >= pi->data_size) {
free(pi->buf);
return 0;
}
ret = sscanf(pi->next, PROC_MTD_PATT, &pi->mtd_num, &pi->size,
&pi->eb_size);
if (ret != 3)
return errmsg("\"%s\" pattern not found", PROC_MTD_PATT);
p = (char*)memchr(pi->next, '\"', pi->data_size - pos);
if (!p)
return errmsg("opening \" not found");
p += 1;
pos = p - pi->buf;
if (pos >= pi->data_size)
return errmsg("opening \" not found");
p1 = (char*)memchr(p, '\"', pi->data_size - pos);
if (!p1)
return errmsg("closing \" not found");
pos = p1 - pi->buf;
if (pos >= pi->data_size)
return errmsg("closing \" not found");
len = p1 - p;
if (len > MTD_NAME_MAX)
return errmsg("too long mtd%d device name", pi->mtd_num);
memcpy(pi->name, p, len);
pi->name[len] = '\0';
if (p1[1] != '\n')
return errmsg("opening \"\n\" not found");
pi->next = p1 + 2;
return 1;
}
/**
* legacy_libmtd_open - legacy version of 'libmtd_open()'.
*
* This function is just checks that MTD is present in the system. Returns
* zero in case of success and %-1 in case of failure. In case of failure,
* errno contains zero if MTD is not present in the system, or contains the
* error code if a real error happened. This is similar to the 'libmtd_open()'
* return conventions.
*/
int legacy_libmtd_open(void)
{
int fd;
fd = open(MTD_PROC_FILE, O_RDONLY);
if (fd == -1) {
if (errno == ENOENT)
errno = 0;
return -1;
}
close(fd);
return 0;
}
/**
* legacy_dev_presentl - legacy version of 'mtd_dev_present()'.
* @info: the MTD device information is returned here
*
* When the kernel does not provide sysfs files for the MTD subsystem,
* fall-back to parsing the /proc/mtd file to determine whether an mtd device
* number @mtd_num is present.
*/
int legacy_dev_present(int mtd_num)
{
int ret;
struct proc_parse_info pi;
ret = proc_parse_start(&pi);
if (ret)
return -1;
while (proc_parse_next(&pi)) {
if (pi.mtd_num == mtd_num)
return 1;
}
return 0;
}
/**
* legacy_mtd_get_info - legacy version of 'mtd_get_info()'.
* @info: the MTD device information is returned here
*
* This function is similar to 'mtd_get_info()' and has the same conventions.
*/
int legacy_mtd_get_info(struct mtd_info *info)
{
int ret;
struct proc_parse_info pi;
ret = proc_parse_start(&pi);
if (ret)
return -1;
info->lowest_mtd_num = INT_MAX;
while (proc_parse_next(&pi)) {
info->mtd_dev_cnt += 1;
if (pi.mtd_num > info->highest_mtd_num)
info->highest_mtd_num = pi.mtd_num;
if (pi.mtd_num < info->lowest_mtd_num)
info->lowest_mtd_num = pi.mtd_num;
}
return 0;
}
/**
* legacy_get_dev_info - legacy version of 'mtd_get_dev_info()'.
* @node: name of the MTD device node
* @mtd: the MTD device information is returned here
*
* This function is similar to 'mtd_get_dev_info()' and has the same
* conventions.
*/
int legacy_get_dev_info(const char *node, struct mtd_dev_info *mtd)
{
struct stat st;
struct mtd_info_user ui;
int fd, ret;
loff_t offs = 0;
struct proc_parse_info pi;
if (stat(node, &st)) {
sys_errmsg("cannot open \"%s\"", node);
if (errno == ENOENT)
normsg("MTD subsystem is old and does not support "
"sysfs, so MTD character device nodes have "
"to exist");
}
if (!S_ISCHR(st.st_mode)) {
errno = EINVAL;
return errmsg("\"%s\" is not a character device", node);
}
memset(mtd, '\0', sizeof(struct mtd_dev_info));
mtd->major = major(st.st_rdev);
mtd->minor = minor(st.st_rdev);
if (mtd->major != MTD_DEV_MAJOR) {
errno = EINVAL;
return errmsg("\"%s\" has major number %d, MTD devices have "
"major %d", node, mtd->major, MTD_DEV_MAJOR);
}
mtd->mtd_num = mtd->minor / 2;
fd = open(node, O_RDONLY);
if (fd == -1)
return sys_errmsg("cannot open \"%s\"", node);
if (ioctl(fd, MEMGETINFO, &ui)) {
sys_errmsg("MEMGETINFO ioctl request failed");
goto out_close;
}
ret = ioctl(fd, MEMGETBADBLOCK, &offs);
if (ret == -1) {
if (errno != EOPNOTSUPP) {
sys_errmsg("MEMGETBADBLOCK ioctl failed");
goto out_close;
}
errno = 0;
mtd->bb_allowed = 0;
} else
mtd->bb_allowed = 1;
mtd->type = ui.type;
mtd->size = ui.size;
mtd->eb_size = ui.erasesize;
mtd->min_io_size = ui.writesize;
mtd->oob_size = ui.oobsize;
if (mtd->min_io_size <= 0) {
errmsg("mtd%d (%s) has insane min. I/O unit size %d",
mtd->mtd_num, node, mtd->min_io_size);
goto out_close;
}
if (mtd->eb_size <= 0 || mtd->eb_size < mtd->min_io_size) {
errmsg("mtd%d (%s) has insane eraseblock size %d",
mtd->mtd_num, node, mtd->eb_size);
goto out_close;
}
if (mtd->size <= 0 || mtd->size < mtd->eb_size) {
errmsg("mtd%d (%s) has insane size %lld",
mtd->mtd_num, node, mtd->size);
goto out_close;
}
mtd->eb_cnt = mtd->size / mtd->eb_size;
switch(mtd->type) {
case MTD_ABSENT:
errmsg("mtd%d (%s) is removable and is not present",
mtd->mtd_num, node);
goto out_close;
case MTD_RAM:
strcpy((char *)mtd->type_str, "ram");
break;
case MTD_ROM:
strcpy((char *)mtd->type_str, "rom");
break;
case MTD_NORFLASH:
strcpy((char *)mtd->type_str, "nor");
break;
case MTD_NANDFLASH:
strcpy((char *)mtd->type_str, "nand");
break;
case MTD_DATAFLASH:
strcpy((char *)mtd->type_str, "dataflash");
break;
case MTD_UBIVOLUME:
strcpy((char *)mtd->type_str, "ubi");
break;
default:
goto out_close;
}
if (ui.flags & MTD_WRITEABLE)
mtd->writable = 1;
mtd->subpage_size = mtd->min_io_size;
close(fd);
/*
* Unfortunately, the device name is not available via ioctl, and
* we have to parse /proc/mtd to get it.
*/
ret = proc_parse_start(&pi);
if (ret)
return -1;
while (proc_parse_next(&pi)) {
if (pi.mtd_num == mtd->mtd_num) {
strcpy((char *)mtd->name, pi.name);
return 0;
}
}
errmsg("mtd%d not found in \"%s\"", mtd->mtd_num, MTD_PROC_FILE);
errno = ENOENT;
return -1;
out_close:
close(fd);
return -1;
}
/**
* legacy_get_dev_info1 - legacy version of 'mtd_get_dev_info1()'.
* @node: name of the MTD device node
* @mtd: the MTD device information is returned here
*
* This function is similar to 'mtd_get_dev_info1()' and has the same
* conventions.
*/
int legacy_get_dev_info1(int mtd_num, struct mtd_dev_info *mtd)
{
char node[sizeof(MTD_DEV_PATT) + 20];
sprintf(node, MTD_DEV_PATT, mtd_num);
return legacy_get_dev_info(node, mtd);
}

View File

@@ -0,0 +1,54 @@
#include <stdint.h>
#define PKT_SIZE 2820
struct image_pkt_hdr {
uint32_t resend;
uint32_t totcrc;
uint32_t nr_blocks;
uint32_t blocksize;
uint32_t block_crc;
uint32_t block_nr;
uint32_t pkt_sequence;
uint16_t pkt_nr;
uint16_t nr_pkts;
uint32_t thislen;
uint32_t thiscrc;
};
struct image_pkt {
struct image_pkt_hdr hdr;
unsigned char data[PKT_SIZE];
};
struct fec_parms;
/* k - number of actual data packets
* n - total number of packets including data and redundant packets
* (actual packet size isn't relevant here) */
struct fec_parms *fec_new(int k, int n);
void fec_free(struct fec_parms *p);
/* src - array of (n) pointers to data packets
* fec - buffer for packet to be generated
* index - index of packet to be generated (0 <= index < n)
* sz - data packet size
*
* _linear version just takes a pointer to the raw data; no
* mucking about with packet pointers.
*/
void fec_encode(struct fec_parms *code, unsigned char *src[],
unsigned char *fec, int index, int sz);
void fec_encode_linear(struct fec_parms *code, unsigned char *src,
unsigned char *fec, int index, int sz);
/* data - array of (k) pointers to data packets, in arbitrary order (see i)
* i - indices of (data) packets
* sz - data packet size
*
* Will never fail as long as you give it (k) individual data packets.
* Will re-order the (data) pointers but not the indices -- data packets
* are ordered on return.
*/
int fec_decode(struct fec_parms *code, unsigned char *data[],
int i[], int sz);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,118 @@
#ifndef __MKFS_JFFS2__
#define __MKFS_JFFS2__
/*
Neutrino-HD
License: GPL
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., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <string>
#include <gui/widget/progresswindow.h>
#include <system/helpers.h>
class CMkfsJFFS2
{
private:
enum {
dev_sys = 0,
dev_proc = 1,
dev_tmp = 2,
/* dev_pts = 3,*/
dev_dev = 3,
dev_jffs2 = 4,
dev_max = 5
};
int out_fd;
std::string rootdir;
int squash_uids;
int squash_perms;
int fake_times;
unsigned long int all_read;
int printProgress;
long kbUsed;
dev_t dev_x[dev_max];
CProgressWindow *progressBar;
int progressBarGlobalX1;
int progressBarGlobalX2;
std::string imageName_, sumName_;
bool useSumtool_;
uint32_t ino;
int out_ofs;
int erase_block_size;
int pad_fs_size;
int add_cleanmarkers;
int cleanmarker_size;
unsigned char ffbuf[16];
bool compressorIsInit;
void Init();
void classClear();
bool classInit();
struct filesystem_entry *recursive_add_host_directory(
struct filesystem_entry *parent, const char *targetpath,
const char *hostpath,
bool skipSpezialFolders);
int parse_device_table(struct filesystem_entry *root, FILE * file);
int interpret_table_entry(struct filesystem_entry *root, char *line);
void create_target_filesystem(struct filesystem_entry *root);
void recursive_populate_directory(struct filesystem_entry *dir);
void padblock(void);
void pad(int req);
inline void padword(void) { if (out_ofs % 4) full_write(out_fd, ffbuf, 4 - (out_ofs % 4)); }
inline void pad_block_if_less_than(int req);
void full_write(int fd, const void *buf, int len);
static uint32_t find_hardlink(struct filesystem_entry *e);
void write_dirent(struct filesystem_entry *e);
void write_special_file(struct filesystem_entry *e);
void write_pipe(struct filesystem_entry *e);
void write_symlink(struct filesystem_entry *e);
unsigned int write_regular_file(struct filesystem_entry *e);
void paintProgressBar();
void setProgressBarGlobal(int x1, int x2);
void printProgressData(bool finish);
struct filesystem_entry *find_filesystem_entry(struct filesystem_entry *dir, char *fullname, uint32_t type);
struct filesystem_entry *add_host_filesystem_entry(const char *name,
const char *path, unsigned long uid, unsigned long gid,
unsigned long mode, dev_t rdev, struct filesystem_entry *parent);
void cleanup(struct filesystem_entry *dir);
char *xreadlink(const char *path);
public:
CMkfsJFFS2();
~CMkfsJFFS2();
bool makeJffs2Image(std::string& path,
std::string& imageName,
int eraseBlockSize=0x20000,
int padFsSize=0,
int addCleanmarkers=0,
int targetEndian=__LITTLE_ENDIAN,
bool skipSpezialFolders=true,
bool useSumtool=true,
CProgressWindow *progress=NULL,
bool useDevTable=true,
std::string devTable="");
};
#endif // __MKFS_JFFS2__

View File

@@ -0,0 +1,390 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org>
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
linux/lib/rbtree.c
*/
#include <stdlib.h>
#include "rbtree.h"
static void __rb_rotate_left(struct rb_node *node, struct rb_root *root)
{
struct rb_node *right = node->rb_right;
struct rb_node *parent = rb_parent(node);
if ((node->rb_right = right->rb_left))
rb_set_parent(right->rb_left, node);
right->rb_left = node;
rb_set_parent(right, parent);
if (parent)
{
if (node == parent->rb_left)
parent->rb_left = right;
else
parent->rb_right = right;
}
else
root->rb_node = right;
rb_set_parent(node, right);
}
static void __rb_rotate_right(struct rb_node *node, struct rb_root *root)
{
struct rb_node *left = node->rb_left;
struct rb_node *parent = rb_parent(node);
if ((node->rb_left = left->rb_right))
rb_set_parent(left->rb_right, node);
left->rb_right = node;
rb_set_parent(left, parent);
if (parent)
{
if (node == parent->rb_right)
parent->rb_right = left;
else
parent->rb_left = left;
}
else
root->rb_node = left;
rb_set_parent(node, left);
}
void rb_insert_color(struct rb_node *node, struct rb_root *root)
{
struct rb_node *parent, *gparent;
while ((parent = rb_parent(node)) && rb_is_red(parent))
{
gparent = rb_parent(parent);
if (parent == gparent->rb_left)
{
{
register struct rb_node *uncle = gparent->rb_right;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_right == node)
{
register struct rb_node *tmp;
__rb_rotate_left(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_right(gparent, root);
} else {
{
register struct rb_node *uncle = gparent->rb_left;
if (uncle && rb_is_red(uncle))
{
rb_set_black(uncle);
rb_set_black(parent);
rb_set_red(gparent);
node = gparent;
continue;
}
}
if (parent->rb_left == node)
{
register struct rb_node *tmp;
__rb_rotate_right(parent, root);
tmp = parent;
parent = node;
node = tmp;
}
rb_set_black(parent);
rb_set_red(gparent);
__rb_rotate_left(gparent, root);
}
}
rb_set_black(root->rb_node);
}
static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
struct rb_root *root)
{
struct rb_node *other;
while ((!node || rb_is_black(node)) && node != root->rb_node)
{
if (parent->rb_left == node)
{
other = parent->rb_right;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_left(parent, root);
other = parent->rb_right;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_right || rb_is_black(other->rb_right))
{
struct rb_node *o_left;
if ((o_left = other->rb_left))
rb_set_black(o_left);
rb_set_red(other);
__rb_rotate_right(other, root);
other = parent->rb_right;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
if (other->rb_right)
rb_set_black(other->rb_right);
__rb_rotate_left(parent, root);
node = root->rb_node;
break;
}
}
else
{
other = parent->rb_left;
if (rb_is_red(other))
{
rb_set_black(other);
rb_set_red(parent);
__rb_rotate_right(parent, root);
other = parent->rb_left;
}
if ((!other->rb_left || rb_is_black(other->rb_left)) &&
(!other->rb_right || rb_is_black(other->rb_right)))
{
rb_set_red(other);
node = parent;
parent = rb_parent(node);
}
else
{
if (!other->rb_left || rb_is_black(other->rb_left))
{
register struct rb_node *o_right;
if ((o_right = other->rb_right))
rb_set_black(o_right);
rb_set_red(other);
__rb_rotate_left(other, root);
other = parent->rb_left;
}
rb_set_color(other, rb_color(parent));
rb_set_black(parent);
if (other->rb_left)
rb_set_black(other->rb_left);
__rb_rotate_right(parent, root);
node = root->rb_node;
break;
}
}
}
if (node)
rb_set_black(node);
}
void rb_erase(struct rb_node *node, struct rb_root *root)
{
struct rb_node *child, *parent;
int color;
if (!node->rb_left)
child = node->rb_right;
else if (!node->rb_right)
child = node->rb_left;
else
{
struct rb_node *old = node, *left;
node = node->rb_right;
while ((left = node->rb_left) != NULL)
node = left;
child = node->rb_right;
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent == old) {
parent->rb_right = child;
parent = node;
} else
parent->rb_left = child;
node->rb_parent_color = old->rb_parent_color;
node->rb_right = old->rb_right;
node->rb_left = old->rb_left;
if (rb_parent(old))
{
if (rb_parent(old)->rb_left == old)
rb_parent(old)->rb_left = node;
else
rb_parent(old)->rb_right = node;
} else
root->rb_node = node;
rb_set_parent(old->rb_left, node);
if (old->rb_right)
rb_set_parent(old->rb_right, node);
goto color;
}
parent = rb_parent(node);
color = rb_color(node);
if (child)
rb_set_parent(child, parent);
if (parent)
{
if (parent->rb_left == node)
parent->rb_left = child;
else
parent->rb_right = child;
}
else
root->rb_node = child;
color:
if (color == RB_BLACK)
__rb_erase_color(child, parent, root);
}
/*
* This function returns the first node (in sort order) of the tree.
*/
struct rb_node *rb_first(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return NULL;
while (n->rb_left)
n = n->rb_left;
return n;
}
struct rb_node *rb_last(struct rb_root *root)
{
struct rb_node *n;
n = root->rb_node;
if (!n)
return NULL;
while (n->rb_right)
n = n->rb_right;
return n;
}
struct rb_node *rb_next(struct rb_node *node)
{
struct rb_node *parent;
if (rb_parent(node) == node)
return NULL;
/* If we have a right-hand child, go down and then left as far
as we can. */
if (node->rb_right) {
node = node->rb_right;
while (node->rb_left)
node=node->rb_left;
return node;
}
/* No right-hand children. Everything down and left is
smaller than us, so any 'next' node must be in the general
direction of our parent. Go up the tree; any time the
ancestor is a right-hand child of its parent, keep going
up. First time it's a left-hand child of its parent, said
parent is our 'next' node. */
while ((parent = rb_parent(node)) && node == parent->rb_right)
node = parent;
return parent;
}
struct rb_node *rb_prev(struct rb_node *node)
{
struct rb_node *parent;
if (rb_parent(node) == node)
return NULL;
/* If we have a left-hand child, go down and then right as far
as we can. */
if (node->rb_left) {
node = node->rb_left;
while (node->rb_right)
node=node->rb_right;
return node;
}
/* No left-hand children. Go up till we find an ancestor which
is a right-hand child of its parent */
while ((parent = rb_parent(node)) && node == parent->rb_left)
node = parent;
return parent;
}
void rb_replace_node(struct rb_node *victim, struct rb_node *new_,
struct rb_root *root)
{
struct rb_node *parent = rb_parent(victim);
/* Set the surrounding nodes to point to the replacement */
if (parent) {
if (victim == parent->rb_left)
parent->rb_left = new_;
else
parent->rb_right = new_;
} else {
root->rb_node = new_;
}
if (victim->rb_left)
rb_set_parent(victim->rb_left, new_);
if (victim->rb_right)
rb_set_parent(victim->rb_right, new_);
/* Copy the pointers/colour from the victim to the replacement */
*new_ = *victim;
}

View File

@@ -0,0 +1,171 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
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
linux/include/linux/rbtree.h
To use rbtrees you'll have to implement your own insert and search cores.
This will avoid us to use callbacks and to drop drammatically performances.
I know it's not the cleaner way, but in C (not in C++) to get
performances and genericity...
Some example of insert and search follows here. The search is a plain
normal search over an ordered tree. The insert instead must be implemented
int two steps: as first thing the code must insert the element in
order as a red leaf in the tree, then the support library function
rb_insert_color() must be called. Such function will do the
not trivial work to rebalance the rbtree if necessary.
-----------------------------------------------------------------------
static inline struct page * rb_search_page_cache(struct inode * inode,
unsigned long offset)
{
struct rb_node * n = inode->i_rb_page_cache.rb_node;
struct page * page;
while (n)
{
page = rb_entry(n, struct page, rb_page_cache);
if (offset < page->offset)
n = n->rb_left;
else if (offset > page->offset)
n = n->rb_right;
else
return page;
}
return NULL;
}
static inline struct page * __rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct rb_node ** p = &inode->i_rb_page_cache.rb_node;
struct rb_node * parent = NULL;
struct page * page;
while (*p)
{
parent = *p;
page = rb_entry(parent, struct page, rb_page_cache);
if (offset < page->offset)
p = &(*p)->rb_left;
else if (offset > page->offset)
p = &(*p)->rb_right;
else
return page;
}
rb_link_node(node, parent, p);
return NULL;
}
static inline struct page * rb_insert_page_cache(struct inode * inode,
unsigned long offset,
struct rb_node * node)
{
struct page * ret;
if ((ret = __rb_insert_page_cache(inode, offset, node)))
goto out;
rb_insert_color(node, &inode->i_rb_page_cache);
out:
return ret;
}
-----------------------------------------------------------------------
*/
#ifndef _LINUX_RBTREE_H
#define _LINUX_RBTREE_H
#include <linux/kernel.h>
#include <linux/stddef.h>
struct rb_node
{
unsigned long rb_parent_color;
#define RB_RED 0
#define RB_BLACK 1
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
/* The alignment might seem pointless, but allegedly CRIS needs it */
struct rb_root
{
struct rb_node *rb_node;
};
#define rb_parent(r) ((struct rb_node *)((r)->rb_parent_color & ~3))
#define rb_color(r) ((r)->rb_parent_color & 1)
#define rb_is_red(r) (!rb_color(r))
#define rb_is_black(r) rb_color(r)
#define rb_set_red(r) do { (r)->rb_parent_color &= ~1; } while (0)
#define rb_set_black(r) do { (r)->rb_parent_color |= 1; } while (0)
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->rb_parent_color = (rb->rb_parent_color & 3) | (unsigned long)p;
}
static inline void rb_set_color(struct rb_node *rb, int color)
{
rb->rb_parent_color = (rb->rb_parent_color & ~1) | color;
}
#define RB_ROOT (struct rb_root) { NULL, }
/* Newer gcc versions take care of exporting this */
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define rb_entry(ptr, type, member) container_of(ptr, type, member)
#define RB_EMPTY_ROOT(root) ((root)->rb_node == NULL)
#define RB_EMPTY_NODE(node) (rb_parent(node) == node)
#define RB_CLEAR_NODE(node) (rb_set_parent(node, node))
extern void rb_insert_color(struct rb_node *, struct rb_root *);
extern void rb_erase(struct rb_node *, struct rb_root *);
/* Find logical next and previous nodes in a tree */
extern struct rb_node *rb_next(struct rb_node *);
extern struct rb_node *rb_prev(struct rb_node *);
extern struct rb_node *rb_first(struct rb_root *);
extern struct rb_node *rb_last(struct rb_root *);
/* Fast replacement of a single node without remove/rebalance/add/rebalance */
extern void rb_replace_node(struct rb_node *victim, struct rb_node *new_,
struct rb_root *root);
static inline void rb_link_node(struct rb_node * node, struct rb_node * parent,
struct rb_node ** rb_link)
{
node->rb_parent_color = (unsigned long )parent;
node->rb_left = node->rb_right = NULL;
*rb_link = node;
}
#endif /* _LINUX_RBTREE_H */

View File

@@ -0,0 +1,177 @@
/*
* JFFS2 -- Journalling Flash File System, Version 2.
*
* Copyright (C) 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>,
* Zoltan Sogor <weth@inf.u-szeged.hu>,
* Patrik Kluba <pajko@halom.u-szeged.hu>,
* University of Szeged, Hungary
*
* For licensing information, see the file 'LICENCE' in this directory.
*/
#ifndef JFFS2_SUMMARY_H
#define JFFS2_SUMMARY_H
#include <linux/jffs2.h>
#define DIRTY_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->dirty_size += _x; \
jeb->free_size -= _x ; jeb->dirty_size += _x; \
}while(0)
#define USED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->used_size += _x; \
jeb->free_size -= _x ; jeb->used_size += _x; \
}while(0)
#define WASTED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->wasted_size += _x; \
jeb->free_size -= _x ; jeb->wasted_size += _x; \
}while(0)
#define UNCHECKED_SPACE(x) do { typeof(x) _x = (x); \
c->free_size -= _x; c->unchecked_size += _x; \
jeb->free_size -= _x ; jeb->unchecked_size += _x; \
}while(0)
#define BLK_STATE_ALLFF 0
#define BLK_STATE_CLEAN 1
#define BLK_STATE_PARTDIRTY 2
#define BLK_STATE_CLEANMARKER 3
#define BLK_STATE_ALLDIRTY 4
#define BLK_STATE_BADBLOCK 5
#define JFFS2_SUMMARY_NOSUM_SIZE 0xffffffff
#define JFFS2_SUMMARY_INODE_SIZE (sizeof(struct jffs2_sum_inode_flash))
#define JFFS2_SUMMARY_DIRENT_SIZE(x) (sizeof(struct jffs2_sum_dirent_flash) + (x))
#define JFFS2_SUMMARY_XATTR_SIZE (sizeof(struct jffs2_sum_xattr_flash))
#define JFFS2_SUMMARY_XREF_SIZE (sizeof(struct jffs2_sum_xref_flash))
/* Summary structures used on flash */
struct jffs2_sum_unknown_flash
{
jint16_t nodetype; /* node type */
} __attribute__((packed));
struct jffs2_sum_inode_flash
{
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_flash
{
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* ofset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
struct jffs2_sum_xattr_flash
{
jint16_t nodetype; /* == JFFS2_NODETYPE_XATR */
jint32_t xid; /* xattr identifier */
jint32_t version; /* version number */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* node length */
} __attribute__((packed));
struct jffs2_sum_xref_flash
{
jint16_t nodetype; /* == JFFS2_NODETYPE_XREF */
jint32_t offset; /* offset on jeb */
} __attribute__((packed));
union jffs2_sum_flash
{
struct jffs2_sum_unknown_flash u;
struct jffs2_sum_inode_flash i;
struct jffs2_sum_dirent_flash d;
struct jffs2_sum_xattr_flash x;
struct jffs2_sum_xref_flash r;
};
/* Summary structures used in the memory */
struct jffs2_sum_unknown_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
} __attribute__((packed));
struct jffs2_sum_inode_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* node type */
jint32_t inode; /* inode number */
jint32_t version; /* inode version */
jint32_t offset; /* offset on jeb */
jint32_t totlen; /* record length */
} __attribute__((packed));
struct jffs2_sum_dirent_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype; /* == JFFS_NODETYPE_DIRENT */
jint32_t totlen; /* record length */
jint32_t offset; /* ofset on jeb */
jint32_t pino; /* parent inode */
jint32_t version; /* dirent version */
jint32_t ino; /* == zero for unlink */
uint8_t nsize; /* dirent name size */
uint8_t type; /* dirent type */
uint8_t name[0]; /* dirent name */
} __attribute__((packed));
struct jffs2_sum_xattr_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype;
jint32_t xid;
jint32_t version;
jint32_t offset;
jint32_t totlen;
} __attribute__((packed));
struct jffs2_sum_xref_mem
{
union jffs2_sum_mem *next;
jint16_t nodetype;
jint32_t offset;
} __attribute__((packed));
union jffs2_sum_mem
{
struct jffs2_sum_unknown_mem u;
struct jffs2_sum_inode_mem i;
struct jffs2_sum_dirent_mem d;
struct jffs2_sum_xattr_mem x;
struct jffs2_sum_xref_mem r;
};
struct jffs2_summary
{
uint32_t sum_size;
uint32_t sum_num;
uint32_t sum_padded;
union jffs2_sum_mem *sum_list_head;
union jffs2_sum_mem *sum_list_tail;
};
/* Summary marker is stored at the end of every sumarized erase block */
struct jffs2_sum_marker
{
jint32_t offset; /* offset of the summary node in the jeb */
jint32_t magic; /* == JFFS2_SUM_MAGIC */
};
#define JFFS2_SUMMARY_FRAME_SIZE (sizeof(struct jffs2_raw_summary) + sizeof(struct jffs2_sum_marker))
#endif

View File

@@ -0,0 +1,766 @@
/*
* sumtool.c
*
* Copyright (C) 2004 Zoltan Sogor <weth@inf.u-szeged.hu>,
* Ferenc Havasi <havasi@inf.u-szeged.hu>
* University of Szeged, Hungary
* 2006 KaiGai Kohei <kaigai@ak.jp.nec.com>
*
* 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.
*
* Overview:
* This is a utility insert summary information into JFFS2 image for
* faster mount time
*
*/
#define PROGRAM_NAME "sumtool"
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <asm/types.h>
#include <dirent.h>
#include <mtd/jffs2-user.h>
#include <endian.h>
#include <byteswap.h>
#include <crc32.h>
#include "summary.h"
#include "common.h"
#include "sumtool.h"
#define PAD(x) (((x)+3)&~3)
struct jffs2_summary *sum_collected = NULL;
extern struct jffs2_unknown_node cleanmarker;
extern int target_endian;
CSumtoolJFFS2::CSumtoolJFFS2()
{
Init();
}
CSumtoolJFFS2::~CSumtoolJFFS2()
{
classClear();
}
bool CSumtoolJFFS2::classInit()
{
out_fd = open(sumName_.c_str(), O_CREAT | O_TRUNC | O_RDWR, 0644);
if (out_fd == -1) {
sys_errmsg("open output file: %s", sumName_.c_str());
return false;
}
in_fd = open(imageName_.c_str(), O_RDONLY);
if (in_fd == -1) {
sys_errmsg("open input file: %s", imageName_.c_str());
return false;
}
init_buffers();
init_sumlist();
return true;
}
void CSumtoolJFFS2::classClear()
{
clean_buffers();
clean_sumlist();
if (in_fd != -1) {
close(in_fd);
in_fd = -1;
}
if (out_fd != -1) {
close(out_fd);
out_fd = -1;
}
}
void CSumtoolJFFS2::Init()
{
verbose = 0;
sum_collected = NULL;
padto = 0; /* pad the output with 0xFF to the end of the final eraseblock */
add_cleanmarkers = 1; /* add cleanmarker to output */
use_input_cleanmarker_size = 1; /* use input file's cleanmarker size (default) */
found_cleanmarkers = 0; /* cleanmarker found in input file */
cleanmarker_size = sizeof(cleanmarker);
erase_block_size = 65536;
out_fd = -1;
in_fd = -1;
data_buffer = NULL; /* buffer for inodes */
data_ofs = 0; /* inode buffer offset */
file_buffer = NULL; /* file buffer contains the actual erase block*/
file_ofs = 0; /* position in the buffer */
imageName_ = "";
sumName_ = "";
memset(ffbuf, 0xFF, sizeof(ffbuf));
}
void CSumtoolJFFS2::setup_cleanmarker(void)
{
cleanmarker.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
cleanmarker.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER);
cleanmarker.totlen = cpu_to_je32(cleanmarker_size);
cleanmarker.hdr_crc = cpu_to_je32(mtd_crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node)-4));
}
void CSumtoolJFFS2::add_sum_inode_mem(union jffs2_node_union *node)
{
struct jffs2_sum_inode_mem *temp = reinterpret_cast<jffs2_sum_inode_mem*>(xmalloc(sizeof(*temp)));
temp->nodetype = node->i.nodetype;
temp->inode = node->i.ino;
temp->version = node->i.version;
temp->offset = cpu_to_je32(data_ofs);
temp->totlen = node->i.totlen;
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
void CSumtoolJFFS2::add_sum_dirent_mem(union jffs2_node_union *node)
{
struct jffs2_sum_dirent_mem *temp = reinterpret_cast<jffs2_sum_dirent_mem*>(xmalloc(sizeof(*temp) + node->d.nsize));
temp->nodetype = node->d.nodetype;
temp->totlen = node->d.totlen;
temp->offset = cpu_to_je32(data_ofs);
temp->pino = node->d.pino;
temp->version = node->d.version;
temp->ino = node->d.ino;
temp->nsize = node->d.nsize;
temp->type = node->d.type;
temp->next = NULL;
memcpy(temp->name,node->d.name,node->d.nsize);
add_sum_mem((union jffs2_sum_mem *) temp);
}
void CSumtoolJFFS2::add_sum_xattr_mem(union jffs2_node_union *node)
{
struct jffs2_sum_xattr_mem *temp = reinterpret_cast<jffs2_sum_xattr_mem*>(xmalloc(sizeof(*temp)));
temp->nodetype = node->x.nodetype;
temp->xid = node->x.xid;
temp->version = node->x.version;
temp->offset = cpu_to_je32(data_ofs);
temp->totlen = node->x.totlen;
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
void CSumtoolJFFS2::add_sum_xref_mem(union jffs2_node_union *node)
{
struct jffs2_sum_xref_mem *temp = reinterpret_cast<jffs2_sum_xref_mem*>(xmalloc(sizeof(*temp)));
temp->nodetype = node->r.nodetype;
temp->offset = cpu_to_je32(data_ofs);
temp->next = NULL;
add_sum_mem((union jffs2_sum_mem *) temp);
}
int CSumtoolJFFS2::add_sum_mem(union jffs2_sum_mem *item)
{
if (!sum_collected->sum_list_head)
sum_collected->sum_list_head = (union jffs2_sum_mem *) item;
if (sum_collected->sum_list_tail)
sum_collected->sum_list_tail->u.next = (union jffs2_sum_mem *) item;
sum_collected->sum_list_tail = (union jffs2_sum_mem *) item;
switch (je16_to_cpu(item->u.nodetype)) {
case JFFS2_NODETYPE_INODE:
sum_collected->sum_size += JFFS2_SUMMARY_INODE_SIZE;
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_DIRENT:
sum_collected->sum_size += JFFS2_SUMMARY_DIRENT_SIZE(item->d.nsize);
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_XATTR:
sum_collected->sum_size += JFFS2_SUMMARY_XATTR_SIZE;
sum_collected->sum_num++;
break;
case JFFS2_NODETYPE_XREF:
sum_collected->sum_size += JFFS2_SUMMARY_XREF_SIZE;
sum_collected->sum_num++;
break;
default:
sys_errmsg("__jffs2_add_sum_mem(): UNKNOWN node type %d\n", je16_to_cpu(item->u.nodetype));
}
return 0;
}
void CSumtoolJFFS2::write_dirent_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu (node->d.totlen),JFFS2_SUMMARY_DIRENT_SIZE(node->d.nsize));
add_sum_dirent_mem(node);
full_write(data_buffer + data_ofs, &(node->d), je32_to_cpu (node->d.totlen));
padword();
}
void CSumtoolJFFS2::write_inode_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu (node->i.totlen),JFFS2_SUMMARY_INODE_SIZE);
add_sum_inode_mem(node); /* Add inode summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->i), je32_to_cpu (node->i.totlen)); /* Write out the inode to inode_buffer */
padword();
}
void CSumtoolJFFS2::write_xattr_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu(node->x.totlen), JFFS2_SUMMARY_XATTR_SIZE);
add_sum_xattr_mem(node); /* Add xdatum summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->x), je32_to_cpu(node->x.totlen));
padword();
}
void CSumtoolJFFS2::write_xref_to_buff(union jffs2_node_union *node)
{
pad_block_if_less_than(je32_to_cpu(node->r.totlen), JFFS2_SUMMARY_XREF_SIZE);
add_sum_xref_mem(node); /* Add xref summary mem to summary list */
full_write(data_buffer + data_ofs, &(node->r), je32_to_cpu(node->r.totlen));
padword();
}
void CSumtoolJFFS2::pad_block_if_less_than(int req,int plus)
{
int datasize = req + plus + sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
if ((int)data_ofs + req > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
}
if (add_cleanmarkers && found_cleanmarkers) {
if (!data_ofs) {
full_write(data_buffer, &cleanmarker, sizeof(cleanmarker));
pad(cleanmarker_size - sizeof(cleanmarker));
padword();
}
}
}
void CSumtoolJFFS2::pad(int req)
{
while (req) {
if (req > (int)sizeof(ffbuf)) {
full_write(data_buffer + data_ofs, ffbuf, sizeof(ffbuf));
req -= sizeof(ffbuf);
} else {
full_write(data_buffer + data_ofs, ffbuf, req);
req = 0;
}
}
}
void CSumtoolJFFS2::full_write(void *target_buff, const void *buf, int len)
{
memcpy(target_buff, buf, len);
data_ofs += len;
}
void CSumtoolJFFS2::write_buff_to_file(void)
{
int len = data_ofs;
uint8_t *buf = NULL;
buf = data_buffer;
while (len > 0) {
int ret = write(out_fd, buf, len);
if (ret < 0)
sys_errmsg("write");
if (ret == 0)
sys_errmsg("write returned zero");
len -= ret;
buf += ret;
}
data_ofs = 0;
}
void CSumtoolJFFS2::dump_sum_records(void)
{
struct jffs2_raw_summary isum;
struct jffs2_sum_marker *sm;
jint32_t offset;
jint32_t *tpage;
char *wpage;
int datasize, infosize, padsize;
jint32_t magic = cpu_to_je32(JFFS2_SUM_MAGIC);
if (!sum_collected->sum_num || !sum_collected->sum_list_head)
return;
datasize = sum_collected->sum_size + sizeof(struct jffs2_sum_marker);
infosize = sizeof(struct jffs2_raw_summary) + datasize;
padsize = erase_block_size - data_ofs - infosize;
infosize += padsize; datasize += padsize;
offset = cpu_to_je32(data_ofs);
tpage = (jint32_t*)xmalloc(datasize);
memset(tpage, 0xff, datasize);
memset(&isum, 0, sizeof(isum));
isum.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
isum.nodetype = cpu_to_je16(JFFS2_NODETYPE_SUMMARY);
isum.totlen = cpu_to_je32(infosize);
isum.hdr_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(struct jffs2_unknown_node) - 4));
isum.padded = cpu_to_je32(0);
if (add_cleanmarkers && found_cleanmarkers) {
isum.cln_mkr = cpu_to_je32(cleanmarker_size);
} else {
isum.cln_mkr = cpu_to_je32(0);
}
isum.sum_num = cpu_to_je32(sum_collected->sum_num);
wpage = (char*)tpage;
while (sum_collected->sum_num) {
switch (je16_to_cpu(sum_collected->sum_list_head->u.nodetype)) {
case JFFS2_NODETYPE_INODE : {
struct jffs2_sum_inode_flash *sino_ptr = reinterpret_cast<jffs2_sum_inode_flash*>(wpage);
sino_ptr->nodetype = sum_collected->sum_list_head->i.nodetype;
sino_ptr->inode = sum_collected->sum_list_head->i.inode;
sino_ptr->version = sum_collected->sum_list_head->i.version;
sino_ptr->offset = sum_collected->sum_list_head->i.offset;
sino_ptr->totlen = sum_collected->sum_list_head->i.totlen;
wpage += JFFS2_SUMMARY_INODE_SIZE;
break;
}
case JFFS2_NODETYPE_DIRENT : {
struct jffs2_sum_dirent_flash *sdrnt_ptr = reinterpret_cast<jffs2_sum_dirent_flash*>(wpage);
sdrnt_ptr->nodetype = sum_collected->sum_list_head->d.nodetype;
sdrnt_ptr->totlen = sum_collected->sum_list_head->d.totlen;
sdrnt_ptr->offset = sum_collected->sum_list_head->d.offset;
sdrnt_ptr->pino = sum_collected->sum_list_head->d.pino;
sdrnt_ptr->version = sum_collected->sum_list_head->d.version;
sdrnt_ptr->ino = sum_collected->sum_list_head->d.ino;
sdrnt_ptr->nsize = sum_collected->sum_list_head->d.nsize;
sdrnt_ptr->type = sum_collected->sum_list_head->d.type;
memcpy(sdrnt_ptr->name, sum_collected->sum_list_head->d.name,
sum_collected->sum_list_head->d.nsize);
wpage += JFFS2_SUMMARY_DIRENT_SIZE(sum_collected->sum_list_head->d.nsize);
break;
}
case JFFS2_NODETYPE_XATTR: {
struct jffs2_sum_xattr_flash *sxattr_ptr = reinterpret_cast<jffs2_sum_xattr_flash*>(wpage);
sxattr_ptr->nodetype = sum_collected->sum_list_head->x.nodetype;
sxattr_ptr->xid = sum_collected->sum_list_head->x.xid;
sxattr_ptr->version = sum_collected->sum_list_head->x.version;
sxattr_ptr->offset = sum_collected->sum_list_head->x.offset;
sxattr_ptr->totlen = sum_collected->sum_list_head->x.totlen;
wpage += JFFS2_SUMMARY_XATTR_SIZE;
break;
}
case JFFS2_NODETYPE_XREF: {
struct jffs2_sum_xref_flash *sxref_ptr = reinterpret_cast<jffs2_sum_xref_flash*>(wpage);
sxref_ptr->nodetype = sum_collected->sum_list_head->r.nodetype;
sxref_ptr->offset = sum_collected->sum_list_head->r.offset;
wpage += JFFS2_SUMMARY_XREF_SIZE;
break;
}
default : {
warnmsg("Unknown node type!\n");
}
}
union jffs2_sum_mem *temp = sum_collected->sum_list_head;
sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
free(temp);
sum_collected->sum_num--;
}
sum_collected->sum_size = 0;
sum_collected->sum_num = 0;
sum_collected->sum_list_tail = NULL;
wpage += padsize;
sm = reinterpret_cast<jffs2_sum_marker*>(wpage);
sm->offset = offset;
sm->magic = magic;
isum.sum_crc = cpu_to_je32(mtd_crc32(0, tpage, datasize));
isum.node_crc = cpu_to_je32(mtd_crc32(0, &isum, sizeof(isum) - 8));
full_write(data_buffer + data_ofs, &isum, sizeof(isum));
full_write(data_buffer + data_ofs, tpage, datasize);
free(tpage);
}
void CSumtoolJFFS2::clean_sumlist(void)
{
if (sum_collected) {
while (sum_collected->sum_list_head) {
union jffs2_sum_mem *temp = sum_collected->sum_list_head;
sum_collected->sum_list_head = sum_collected->sum_list_head->u.next;
free(temp);
sum_collected->sum_num--;
}
if (sum_collected->sum_num != 0)
warnmsg("Ooops, something wrong happened! sum_num != 0, but sum_list = null ???");
free(sum_collected);
sum_collected = NULL;
}
}
void CSumtoolJFFS2::flush_buffers(void)
{
if ((add_cleanmarkers == 1) && (found_cleanmarkers == 1)) { /* CLEANMARKER */
if ((int)data_ofs != cleanmarker_size) { /* INODE BUFFER */
int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
/* If we have a full inode buffer, then write out inode and summary data */
if ((int)data_ofs + (int)sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
} else { /* else just write out inode data */
if (padto)
pad(erase_block_size - data_ofs);
write_buff_to_file();
}
}
} else { /* NO CLEANMARKER */
if (data_ofs != 0) { /* INODE BUFFER */
int datasize = sum_collected->sum_size + sizeof(struct jffs2_raw_summary) + 8;
datasize += (4 - (datasize % 4)) % 4;
/* If we have a full inode buffer, then write out inode and summary data */
if ((int)data_ofs + (int)sizeof(struct jffs2_raw_inode) + 2*JFFS2_MIN_DATA_LEN > erase_block_size - datasize) {
dump_sum_records();
write_buff_to_file();
} else { /* Else just write out inode data */
if (padto)
pad(erase_block_size - data_ofs);
write_buff_to_file();
}
}
}
}
void CSumtoolJFFS2::create_summed_image(int inp_size)
{
uint8_t *p = file_buffer;
union jffs2_node_union *node;
uint32_t crc, length;
uint16_t type;
int bitchbitmask = 0;
int obsolete;
char name[256];
while ( p < (file_buffer + inp_size)) {
node = (union jffs2_node_union *) p;
/* Skip empty space */
if (je16_to_cpu (node->u.magic) == 0xFFFF && je16_to_cpu (node->u.nodetype) == 0xFFFF) {
p += 4;
continue;
}
if (je16_to_cpu (node->u.magic) != JFFS2_MAGIC_BITMASK) {
if (!bitchbitmask++)
warnmsg("Wrong bitmask at 0x%08zx, 0x%04x\n",
p - file_buffer, je16_to_cpu (node->u.magic));
p += 4;
continue;
}
bitchbitmask = 0;
type = je16_to_cpu(node->u.nodetype);
if ((type & JFFS2_NODE_ACCURATE) != JFFS2_NODE_ACCURATE) {
obsolete = 1;
type |= JFFS2_NODE_ACCURATE;
} else {
obsolete = 0;
}
node->u.nodetype = cpu_to_je16(type);
crc = mtd_crc32 (0, node, sizeof (struct jffs2_unknown_node) - 4);
if (crc != je32_to_cpu (node->u.hdr_crc)) {
warnmsg("Wrong hdr_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu (node->u.hdr_crc), crc);
p += 4;
continue;
}
switch (je16_to_cpu(node->u.nodetype)) {
case JFFS2_NODETYPE_INODE:
bareverbose(verbose,
"%8s Inode node at 0x%08zx, totlen 0x%08x, #ino %5d, version %5d, isize %8d, csize %8d, dsize %8d, offset %8d\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->i.totlen), je32_to_cpu (node->i.ino),
je32_to_cpu (node->i.version), je32_to_cpu (node->i.isize),
je32_to_cpu (node->i.csize), je32_to_cpu (node->i.dsize), je32_to_cpu (node->i.offset));
crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_inode) - 8);
if (crc != je32_to_cpu (node->i.node_crc)) {
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu (node->i.node_crc), crc);
p += PAD(je32_to_cpu (node->i.totlen));
continue;
}
crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_inode), je32_to_cpu(node->i.csize));
if (crc != je32_to_cpu(node->i.data_crc)) {
warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu (node->i.data_crc), crc);
p += PAD(je32_to_cpu (node->i.totlen));
continue;
}
write_inode_to_buff(node);
p += PAD(je32_to_cpu (node->i.totlen));
break;
case JFFS2_NODETYPE_DIRENT:
memcpy (name, node->d.name, node->d.nsize);
name [node->d.nsize] = 0x0;
bareverbose(verbose,
"%8s Dirent node at 0x%08zx, totlen 0x%08x, #pino %5d, version %5d, #ino %8d, nsize %8d, name %s\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->d.totlen), je32_to_cpu (node->d.pino),
je32_to_cpu (node->d.version), je32_to_cpu (node->d.ino),
node->d.nsize, name);
crc = mtd_crc32 (0, node, sizeof (struct jffs2_raw_dirent) - 8);
if (crc != je32_to_cpu (node->d.node_crc)) {
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu (node->d.node_crc), crc);
p += PAD(je32_to_cpu (node->d.totlen));
continue;
}
crc = mtd_crc32(0, p + sizeof (struct jffs2_raw_dirent), node->d.nsize);
if (crc != je32_to_cpu(node->d.name_crc)) {
warnmsg("Wrong name_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu (node->d.name_crc), crc);
p += PAD(je32_to_cpu (node->d.totlen));
continue;
}
write_dirent_to_buff(node);
p += PAD(je32_to_cpu (node->d.totlen));
break;
case JFFS2_NODETYPE_XATTR:
if (je32_to_cpu(node->x.node_crc) == 0xffffffff)
obsolete = 1;
bareverbose(verbose,
"%8s Xdatum node at 0x%08zx, totlen 0x%08x, #xid %5u, version %5u\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->x.totlen),
je32_to_cpu(node->x.xid), je32_to_cpu(node->x.version));
crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xattr) - 4);
if (crc != je32_to_cpu(node->x.node_crc)) {
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->x.node_crc), crc);
p += PAD(je32_to_cpu (node->x.totlen));
continue;
}
length = node->x.name_len + 1 + je16_to_cpu(node->x.value_len);
crc = mtd_crc32(0, node->x.data, length);
if (crc != je32_to_cpu(node->x.data_crc)) {
warnmsg("Wrong data_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->x.data_crc), crc);
p += PAD(je32_to_cpu (node->x.totlen));
continue;
}
write_xattr_to_buff(node);
p += PAD(je32_to_cpu (node->x.totlen));
break;
case JFFS2_NODETYPE_XREF:
if (je32_to_cpu(node->r.node_crc) == 0xffffffff)
obsolete = 1;
bareverbose(verbose,
"%8s Xref node at 0x%08zx, totlen 0x%08x, #ino %5u, xid %5u\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu(node->r.totlen),
je32_to_cpu(node->r.ino), je32_to_cpu(node->r.xid));
crc = mtd_crc32(0, node, sizeof (struct jffs2_raw_xref) - 4);
if (crc != je32_to_cpu(node->r.node_crc)) {
warnmsg("Wrong node_crc at 0x%08zx, 0x%08x instead of 0x%08x\n",
p - file_buffer, je32_to_cpu(node->r.node_crc), crc);
p += PAD(je32_to_cpu (node->r.totlen));
continue;
}
write_xref_to_buff(node);
p += PAD(je32_to_cpu (node->r.totlen));
break;
case JFFS2_NODETYPE_CLEANMARKER:
bareverbose(verbose,
"%8s Cleanmarker at 0x%08zx, totlen 0x%08x\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->u.totlen));
if (!found_cleanmarkers) {
found_cleanmarkers = 1;
if (add_cleanmarkers == 1 && use_input_cleanmarker_size == 1) {
cleanmarker_size = je32_to_cpu (node->u.totlen);
setup_cleanmarker();
}
}
p += PAD(je32_to_cpu (node->u.totlen));
break;
case JFFS2_NODETYPE_PADDING:
bareverbose(verbose,
"%8s Padding node at 0x%08zx, totlen 0x%08x\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->u.totlen));
p += PAD(je32_to_cpu (node->u.totlen));
break;
case 0xffff:
p += 4;
break;
default:
bareverbose(verbose,
"%8s Unknown node at 0x%08zx, totlen 0x%08x\n",
obsolete ? "Obsolete" : "",
p - file_buffer, je32_to_cpu (node->u.totlen));
p += PAD(je32_to_cpu (node->u.totlen));
}
}
}
int CSumtoolJFFS2::load_next_block(void)
{
int ret;
ret = read(in_fd, file_buffer, erase_block_size);
file_ofs = 0;
bareverbose(verbose, "Load next block : %d bytes read\n", ret);
return ret;
}
void CSumtoolJFFS2::init_buffers(void)
{
if (data_buffer == NULL)
data_buffer = (uint8_t*)xmalloc(erase_block_size);
if (file_buffer == NULL)
file_buffer = (uint8_t*)xmalloc(erase_block_size);
}
void CSumtoolJFFS2::init_sumlist(void)
{
if (sum_collected == NULL)
sum_collected = reinterpret_cast<jffs2_summary*>(xzalloc(sizeof(*sum_collected)));
}
void CSumtoolJFFS2::clean_buffers(void)
{
if (data_buffer != NULL) {
free(data_buffer);
data_buffer = NULL;
}
if (file_buffer != NULL) {
free(file_buffer);
file_buffer = NULL;
}
}
bool CSumtoolJFFS2::sumtool(std::string& imageName,
std::string& sumName,
int eraseBlockSize/*=0x20000*/,
int padTo/*=0*/,
int addCleanmarkers/*=0*/,
int targetEndian/*=__LITTLE_ENDIAN*/)
{
Init();
imageName_ = imageName;
sumName_ = sumName;
erase_block_size = eraseBlockSize; // -e
padto = padTo; // -p
add_cleanmarkers = addCleanmarkers; // -n
target_endian = targetEndian; // -l
classInit();
int ret;
while ((ret = load_next_block())) {
create_summed_image(ret);
}
flush_buffers();
classClear();
printf("##### sumtool OK.\n");
return true;
}

View File

@@ -0,0 +1,87 @@
#ifndef __SUMTOOL_JFFS2__
#define __SUMTOOL_JFFS2__
/*
Neutrino-HD
License: GPL
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., 51 Franklin St, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include <string>
class CSumtoolJFFS2
{
private:
int verbose;
int padto;
int add_cleanmarkers;
int use_input_cleanmarker_size;
int found_cleanmarkers;
int cleanmarker_size;
int erase_block_size;
int out_fd;
int in_fd;
uint8_t *data_buffer;
unsigned int data_ofs;
uint8_t *file_buffer;
unsigned int file_ofs;
unsigned char ffbuf[16];
std::string imageName_, sumName_;
void Init();
void classClear();
bool classInit();
void clean_buffers(void);
static void init_sumlist(void);
void init_buffers(void);
int load_next_block(void);
void create_summed_image(int inp_size);
void flush_buffers(void);
static void clean_sumlist(void);
void dump_sum_records(void);
void write_buff_to_file(void);
void full_write(void *target_buff, const void *buf, int len);
void pad(int req);
inline void padword(void) { if (data_ofs % 4) full_write(data_buffer + data_ofs, ffbuf, 4 - (data_ofs % 4)); }
inline void pad_block_if_less_than(int req,int plus);
void write_xref_to_buff(union jffs2_node_union *node);
void write_xattr_to_buff(union jffs2_node_union *node);
void write_inode_to_buff(union jffs2_node_union *node);
void write_dirent_to_buff(union jffs2_node_union *node);
static int add_sum_mem(union jffs2_sum_mem *item);
void add_sum_xref_mem(union jffs2_node_union *node);
void add_sum_xattr_mem(union jffs2_node_union *node);
void add_sum_dirent_mem(union jffs2_node_union *node);
void add_sum_inode_mem(union jffs2_node_union *node);
void setup_cleanmarker(void);
public:
CSumtoolJFFS2();
~CSumtoolJFFS2();
bool sumtool(std::string& imageName,
std::string& sumName,
int eraseBlockSize=0x20000,
int padTo=0,
int addCleanmarkers=0,
int targetEndian=__LITTLE_ENDIAN);
};
#endif // __SUMTOOL_JFFS2__