cal: Added CAL parser from Calvaria

This commit is contained in:
Pali Rohár committed 2012-11-24 00:54:01 +01:00
1 parent 9087b564ba
commit c03e01879e
3 files changed
+299 -1

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@ CPPFLAGS += -DVERSION=\"$(VERSION)\" -D_GNU_SOURCE -I.
CFLAGS += -W -Wall -O2 -pedantic -std=c99
LIBS += -lm -lusb
OBJS = main.o nolo.o printf-utils.o image.o fiasco.o device.o usb-device.o cold-flash.o qmode.o console.o squeue/squeue.o operations.o local.o mkii.o disk.o
OBJS = main.o nolo.o printf-utils.o image.o fiasco.o device.o usb-device.o cold-flash.o qmode.o console.o squeue/squeue.o operations.o local.o mkii.o disk.o cal.o
BIN = 0xFFFF
all: $(BIN)
+263
View File
@@ -0,0 +1,263 @@
/*
0xFFFF - Open Free Fiasco Firmware Flasher
Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
*/
/* This is simple CAL parser form Calvaria */
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <linux/fs.h>
#include <mtd/mtd-user.h>
#include "cal.h"
#define MAX_SIZE 393216
#define INDEX_LAST (0xFF + 1)
#define HDR_MAGIC "ConF"
struct cal {
int fd;
ssize_t size;
void * mem;
};
struct header {
char magic[4]; /* Magic sequence */
uint8_t type; /* Type number */
uint8_t index; /* Index number */
uint16_t flags; /* Flags */
char name[16]; /* Human readable section name */
uint32_t length; /* Payload length */
uint32_t datasum; /* Data CRC32 checksum */
uint32_t hdrsum; /* Header CRC32 checksum */
} __attribute__((__packed__));
int cal_init_file(const char * file, struct cal ** cal_out) {
int fd = -1;
uint64_t blksize = 0;
ssize_t size = 0;
void * mem = NULL;
struct cal * cal = NULL;
struct stat st;
mtd_info_t mtd_info;
if ( stat(file, &st) != 0 )
return -1;
fd = open(file, O_RDONLY);
if ( fd < 0 )
return -1;
if ( S_ISREG(st.st_mode) )
size = st.st_size;
else if ( S_ISBLK(st.st_mode) ) {
if ( ioctl(fd, BLKGETSIZE64, &blksize) != 0 )
goto err;
if ( blksize > SSIZE_MAX )
goto err;
size = blksize;
} else if ( S_ISCHR(st.st_mode) && major(st.st_rdev) == 90 ) {
if ( ioctl(fd, MEMGETINFO, &mtd_info) != 0 )
goto err;
size = mtd_info.size;
} else {
goto err;
}
if ( size == 0 || size > MAX_SIZE )
goto err;
mem = malloc(size);
if ( ! mem )
goto err;
if ( read(fd, mem, size) != size )
goto err;
cal = malloc(sizeof(struct cal));
if ( ! cal )
goto err;
cal->fd = fd;
cal->mem = mem;
cal->size = size;
*cal_out = cal;
return 0;
err:
close(fd);
free(mem);
return -1;
}
int cal_init(struct cal ** cal_out) {
return cal_init_file("/dev/mtd1ro", cal_out);
}
void cal_finish(struct cal * cal) {
if ( cal ) {
free(cal->mem);
free(cal);
}
}
static uint32_t crc32(uint32_t crc, const void * _data, size_t size) {
const uint8_t * data = _data;
uint8_t value;
unsigned int bit;
size_t i;
const uint32_t poly = 0xEDB88320;
for ( i = 0; i < size; i++ ) {
value = data[i];
for ( bit = 8; bit; bit-- ) {
if ( (crc & 1) != (value & 1) )
crc = (crc >> 1) ^ poly;
else
crc >>= 1;
value >>= 1;
}
}
return crc;
}
static int is_header(void *data, size_t size) {
struct header * hdr = data;
if ( size < sizeof(struct header) )
return 0;
if ( memcmp(hdr->magic, HDR_MAGIC, sizeof(hdr->magic)) != 0 )
return 0;
return 1;
}
static int64_t find_section(void *start, uint64_t count, int want_index, const char *want_name) {
int64_t offset = 0, found_offset = -1;
uint8_t * data = start;
struct header *hdr;
char sectname[sizeof(hdr->name) + 1] = { 0, };
uint32_t payload_len;
int previous_index = -1;
while ( 1 ) {
/* Find header start */
if ( count < sizeof(struct header) )
break;
if ( ! is_header(data + offset, count) ) {
count--;
offset++;
continue;
}
hdr = (struct header *)(data + offset);
payload_len = hdr->length;
if ( count - sizeof(struct header) < payload_len )
return -1;
memcpy(sectname, hdr->name, sizeof(hdr->name));
if ( want_index == INDEX_LAST ) {
if ((int)hdr->index <= previous_index)
goto next;
} else {
if (want_index >= 0 && want_index != hdr->index)
goto next;
}
if ( want_name && strcmp(sectname, want_name) != 0 )
goto next;
/* Found it */
found_offset = offset;
if ( want_index == INDEX_LAST )
previous_index = hdr->index;
else
break;
next:
count -= sizeof(struct header) + payload_len;
offset += sizeof(struct header) + payload_len;
}
return found_offset;
}
int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags) {
int64_t find_offset;
uint64_t filelen = cal->size;
uint8_t * data = cal->mem;
struct header * hdr;
find_offset = find_section(data, filelen, INDEX_LAST, name);
if ( find_offset < 0 )
return -1;
hdr = (struct header *)(data + find_offset);
if ( flags && hdr->flags != flags )
return -1;
if ( crc32(0, hdr, sizeof(*hdr) - 4) != hdr->hdrsum )
return -1;
*ptr = data + find_offset + sizeof(struct header);
*len = hdr->length;
if ( crc32(0, *ptr, *len) != hdr->datasum )
return -1;
return 0;
}
+35
View File
@@ -0,0 +1,35 @@
/*
0xFFFF - Open Free Fiasco Firmware Flasher
Copyright (c) 2011 Michael Buesch <mb@bu3sch.de>
Copyright (C) 2012 Pali Rohár <pali.rohar@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
*/
#ifndef CAL_H
#define CAL_H
#define CAL_MAX_NAME_LEN 16
#define CAL_FLAG_USER 0x0001
#define CAL_FLAG_WRITE_ONCE 0x0002
struct cal;
int cal_init(struct cal ** cal_out);
int cal_init_file(const char * file, struct cal ** cal_out);
void cal_finish(struct cal * cal);
int cal_read_block(struct cal * cal, const char * name, void ** ptr, unsigned long * len, unsigned long flags);
#endif