Stefan Reinauer has uploaded this change for review. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Right now we are parsing the config files into em100pro_chips.h and expect the users to deal with firmware by themselves. With a simple tar implementation we could bundle the original files with the binary much easier.
DO NOT COMMIT
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- A configs.tar A firmware.tar A tar.c 3 files changed, 217 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/1
diff --git a/configs.tar b/configs.tar new file mode 100644 index 0000000..3d71d71 --- /dev/null +++ b/configs.tar Binary files differ diff --git a/firmware.tar b/firmware.tar new file mode 100644 index 0000000..10ed9d9 --- /dev/null +++ b/firmware.tar Binary files differ diff --git a/tar.c b/tar.c new file mode 100644 index 0000000..6f4a117 --- /dev/null +++ b/tar.c @@ -0,0 +1,217 @@ +#define _GNU_SOURCE +//#define DEBUG +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +/* Debugging */ +#include <stdint.h> +#include <ctype.h> +static void hexdump(const void *memory, size_t length) +{ + int i; + uint8_t *m; + int all_zero = 0; + int all_one = 0; + + m = (uint8_t *) memory; + + for (i = 0; i < length; i += 16) { + int j; + + all_zero++; + all_one++; + for (j = 0; j < 16; j++) { + if (m[i + j] != 0) { + all_zero = 0; + break; + } + } + for (j = 0; j < 16; j++) { + if (m[i + j] != 0xff) { + all_one = 0; + break; + } + } + if (all_zero < 2 && all_one < 2) { + printf( "%08x:", i); + for (j = 0; j < 16; j++) + printf( " %02x", m[i + j]); + printf(" "); + for (j = 0; j < 16; j++) + printf( "%c", + isprint(m[i + j]) ? m[i + j] : '.'); + printf( "\n"); + } else if (all_zero == 2 || all_one == 2) { + printf( "...\n"); + } + } +} +/* Debugging */ + +#define ROUND_UP(n, inc) (n + (inc - n % inc) % inc) + +typedef struct { + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char type; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char padding[12]; +} __attribute__((packed)) tar_raw_header_t; + +static unsigned int checksum(tar_raw_header_t *file) +{ + int i, chk_off = offsetof(tar_raw_header_t, checksum); + char *raw = (char *)file; + unsigned int chksum = 256; + + for (i = 0; i < sizeof(tar_raw_header_t); i++) { + if (i >= chk_off && i < chk_off + 8) + continue; + chksum += raw[i]; + } + return chksum; +} + +int tar_ls(char *tar, size_t tar_length) +{ + size_t i = 0; + + while (i < tar_length) { + tar_raw_header_t *f = (tar_raw_header_t *)(tar + i); + if (f->name[0] == 0) /* null header at end of tar */ + break; + + unsigned int size = strtol(f->size, NULL, 8); + unsigned int cksum = strtol(f->checksum, NULL, 8); + unsigned int ok = (checksum(f) == cksum); + + if(!ok) + break; + + printf("name: "%s" (%s)\n", f->name, ok?"OK":"FAIL"); +#ifdef DEBUG + printf(" mode: "%s"\n", f->mode); + printf(" owner: "%s"\n", f->owner); + printf(" group: "%s"\n", f->group); + printf(" size: %011o\n", size); + printf(" mtime: "%s"\n", f->mtime); + printf(" checksum: %07o\n", cksum); + char *t; + switch (f->type) { + case '0': t = "regular"; break; + case '1': t = "link"; break; + case '2': t = "reserved"; break; + case '3': t = "character special"; break; + case '4': t = "block special"; break; + case '5': t = "directory"; break; + case '6': t = "fifo special" break; + case '7': t = "contiguous"; break; + default: t = "<unknown>"; break; + } + printf(" type: %s\n", t); + printf(" linkname: "%s"\n\n", strndupa(f->linkname, 100)); +#endif + + i += sizeof(tar_raw_header_t) + ROUND_UP(size, 512); + } + + return 0; +} + +int tar_find(char *tar, size_t tar_length, char *name, char **result, size_t *result_length) +{ + size_t i = 0; + + while (i < tar_length) { + tar_raw_header_t *f = (tar_raw_header_t *)(tar + i); + if (f->name[0] == 0) /* null header at end of tar */ + break; + + unsigned int size = strtol(f->size, NULL, 8); + unsigned int cksum = strtol(f->checksum, NULL, 8); + unsigned int ok = (checksum(f) == cksum); + + if(!ok) + break; + + if (!strncmp(name, f->name, 100) && f->type == '0') { + *result = tar + i + sizeof(tar_raw_header_t); + *result_length = size; + return 0; + } + i += sizeof(tar_raw_header_t) + ROUND_UP(size, 512); + } + + return 1; +} + +int main(int argc, char *argv[]) +{ + FILE *f; + size_t fsize; + char *fw; + + char *filename = "firmware.tar"; + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + return 0; + } + + fseek(f, 0, SEEK_END); + fsize = ftell(f); + if (fsize < 0) { + perror(filename); + fclose(f); + return 0; + } + fseek(f, 0, SEEK_SET); + + fw = malloc(fsize); + if (!fw) { + printf("ERROR: out of memory.\n"); + fclose(f); + return 0; + } + if (fread(fw, fsize, 1, f) != 1) { + perror(filename); + fclose(f); + free(fw); + return 0; + } + fclose(f); + + tar_ls(fw, fsize); + + char *img; + size_t img_length; + int ret; + + ret = tar_find(fw, fsize, "firmware/em100pro_fw_2.27_0.89_3.3V.dpfw", + &img, &img_length); + + if (ret) { + printf("FILE NOT FOUND\n"); + } else { + printf("firmware/em100pro_fw_2.27_0.89_3.3V.dpfw:\n\n"); + hexdump(img, img_length); + } + + free(fw); +} +
Hello build bot (Jenkins),
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#2).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Right now we are parsing the config files into em100pro_chips.h and expect the users to deal with firmware by themselves. With a simple tar implementation we could bundle the original files with the binary much easier.
DO NOT COMMIT
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A configs.tar A firmware.tar A tar.c 4 files changed, 193 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/2
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#3).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Right now we are parsing the config files into em100pro_chips.h and expect the users to deal with firmware by themselves. With a simple tar implementation we could bundle the original files with the binary much easier.
DO NOT COMMIT
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A configs.tar A firmware.tar A tar.c 4 files changed, 193 insertions(+), 1 deletion(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/3
Patrick Georgi has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
Patch Set 3:
Interesting idea, but the tar reader seems to be home-grown, which won't bode well with a format that probably has more variations than there are em100s out there.
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#4).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Right now we are parsing the config files into em100pro_chips.h and expect the users to deal with firmware by themselves. With a simple tar implementation we could bundle the original files with the binary much easier.
DO NOT COMMIT
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile M em100.c M em100.h A tar.c A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 14 files changed, 3,902 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/4
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
Patch Set 4:
Patch Set 3:
Interesting idea, but the tar reader seems to be home-grown, which won't bode well with a format that probably has more variations than there are em100s out there.
I'll worry about that when I see a tar version that causes trouble. So far all systems I have tried worked fine with the system tar. We're somewhat safe here, because we never have to compile this for machines that do not have USB.
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#7).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Right now we are parsing the config files into em100pro_chips.h and expect the users to deal with firmware by themselves. With a simple tar implementation we could bundle the original files with the binary much easier.
DO NOT COMMIT
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile M em100.c M em100.h A tar.c A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 14 files changed, 3,939 insertions(+), 5 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/7
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#8).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
DO NOT COMMIT. STILL UNDER TESTING AND CLEANUP.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A chips.c M em100.c M em100.h A tar.c A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 15 files changed, 4,370 insertions(+), 44 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/8
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#10).
Change subject: WIP: Use binaries from Windows installer directly ......................................................................
WIP: Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
DO NOT COMMIT. STILL UNDER TESTING AND CLEANUP.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A chips.c M em100.c M em100.h A tar.c A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 15 files changed, 4,369 insertions(+), 42 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/10
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#11).
Change subject: Use binaries from Windows installer directly ......................................................................
Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A chips.c M em100.c M em100.h A tar.c A xz/README A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 16 files changed, 4,366 insertions(+), 42 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/11
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 11:
(1 comment)
https://review.coreboot.org/c/em100/+/36943/11/chips.c File chips.c:
https://review.coreboot.org/c/em100/+/36943/11/chips.c@2 PS11, Line 2: Copyright 2012 Google Inc. This used to be makechips.c basically
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 11:
(4 comments)
https://review.coreboot.org/c/em100/+/36943/11/em100.h File em100.h:
https://review.coreboot.org/c/em100/+/36943/11/em100.h@191 PS11, Line 191: /* Network */ : void download(char *name, char *id); : int update_all_files(void); : move to network patchset
https://review.coreboot.org/c/em100/+/36943/11/em100.h@199 PS11, Line 199: //char *get_em100_home(void); drop
https://review.coreboot.org/c/em100/+/36943/11/em100.c File em100.c:
https://review.coreboot.org/c/em100/+/36943/11/em100.c@665 PS11, Line 665: drop
https://review.coreboot.org/c/em100/+/36943/11/em100.c@693 PS11, Line 693: // Previously we would just return the first chip if desiredchip was : // not set. TODO figure out the right behavior. : Hence the if(desiredchip ...) further down
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 11:
(1 comment)
https://review.coreboot.org/c/em100/+/36943/11/tar.c File tar.c:
https://review.coreboot.org/c/em100/+/36943/11/tar.c@292 PS11, Line 292: #if 0 : int test_tar(void) : { : TFILE *firmware; : TFILE *tfile = tar_load_compressed(get_em100_file("firmware.tar.xz")); : if (!tfile) { : printf("firmware.tar.xz not found.\n"); : return 1; : } : : tar_ls(tfile); : firmware = tar_find(tfile, "firmware/em100pro_fw_2.27_0.89_3.3V.dpfw"); : if (!firmware) { : printf("File not found.\n"); : tar_close(tfile); : return 1; : } : : hexdump(firmware->address, 76); : : tar_close(tfile); : : return 0; : } : #endif : drop
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 11:
(6 comments)
https://review.coreboot.org/c/em100/+/36943/11/chips.c File chips.c:
https://review.coreboot.org/c/em100/+/36943/11/chips.c@2 PS11, Line 2: Copyright 2012 Google Inc.
This used to be makechips. […]
Done
https://review.coreboot.org/c/em100/+/36943/11/em100.h File em100.h:
https://review.coreboot.org/c/em100/+/36943/11/em100.h@191 PS11, Line 191: /* Network */ : void download(char *name, char *id); : int update_all_files(void); :
move to network patchset
Done
https://review.coreboot.org/c/em100/+/36943/11/em100.h@199 PS11, Line 199: //char *get_em100_home(void);
drop
Done
https://review.coreboot.org/c/em100/+/36943/11/em100.c File em100.c:
https://review.coreboot.org/c/em100/+/36943/11/em100.c@665 PS11, Line 665:
drop
Done
https://review.coreboot.org/c/em100/+/36943/11/em100.c@693 PS11, Line 693: // Previously we would just return the first chip if desiredchip was : // not set. TODO figure out the right behavior. :
Hence the if(desiredchip ... […]
Done
https://review.coreboot.org/c/em100/+/36943/11/tar.c File tar.c:
https://review.coreboot.org/c/em100/+/36943/11/tar.c@292 PS11, Line 292: #if 0 : int test_tar(void) : { : TFILE *firmware; : TFILE *tfile = tar_load_compressed(get_em100_file("firmware.tar.xz")); : if (!tfile) { : printf("firmware.tar.xz not found.\n"); : return 1; : } : : tar_ls(tfile); : firmware = tar_find(tfile, "firmware/em100pro_fw_2.27_0.89_3.3V.dpfw"); : if (!firmware) { : printf("File not found.\n"); : tar_close(tfile); : return 1; : } : : hexdump(firmware->address, 76); : : tar_close(tfile); : : return 0; : } : #endif :
drop
Done
Hello build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#12).
Change subject: Use binaries from Windows installer directly ......................................................................
Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A chips.c M em100.c M em100.h A tar.c A xz/README A xz/xz.h A xz/xz_config.h A xz/xz_crc32.c A xz/xz_crc64.c A xz/xz_dec_bcj.c A xz/xz_dec_lzma2.c A xz/xz_dec_stream.c A xz/xz_lzma2.h A xz/xz_private.h A xz/xz_stream.h 16 files changed, 4,345 insertions(+), 46 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/12
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 12:
I'd suggest adding the xz code in a separate commit, so that the changes are easier to review.
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 13:
Patch Set 12:
I'd suggest adding the xz code in a separate commit, so that the changes are easier to review.
I'm curious to see if that helps, as the code was very separate before already. But here you go. :-)
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 13: Code-Review+1
(5 comments)
Patch Set 13:
Patch Set 12:
I'd suggest adding the xz code in a separate commit, so that the changes are easier to review.
I'm curious to see if that helps, as the code was very separate before already. But here you go. :-)
It does help! Large changes make Gerrit unbearably sluggish :-P
https://review.coreboot.org/c/em100/+/36943/13/em100.c File em100.c:
https://review.coreboot.org/c/em100/+/36943/13/em100.c@656 PS13, Line 656: static int list_chips_entry(char *name __unused, TFILE *file, void *data __unused, int ok __unused) Sanity check: the return value is always the same. Is this intended? If it is, maybe move the printf() call into the if block instead?
https://review.coreboot.org/c/em100/+/36943/13/em100.c@693 PS13, Line 693: dcfg Sanity check: Is it needed to call `tar_close(dcfg)` before returning?
https://review.coreboot.org/c/em100/+/36943/13/em100.c@989 PS13, Line 989: const Why is this const if its value gets modified by `get_chip_type()`?
https://review.coreboot.org/c/em100/+/36943/13/tar.c File tar.c:
https://review.coreboot.org/c/em100/+/36943/13/tar.c@87 PS13, Line 87: if(!ok) missing space
https://review.coreboot.org/c/em100/+/36943/13/tar.c@121 PS13, Line 121: if(!ok) missing space
Hello Angel Pons, build bot (Jenkins), Patrick Georgi, Martin Roth,
I'd like you to reexamine a change. Please visit
https://review.coreboot.org/c/em100/+/36943
to look at the new patch set (#14).
Change subject: Use binaries from Windows installer directly ......................................................................
Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org --- M Makefile A chips.c M em100.c M em100.h A tar.c 5 files changed, 775 insertions(+), 46 deletions(-)
git pull ssh://review.coreboot.org:29418/em100 refs/changes/43/36943/14
Stefan Reinauer has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 14:
(5 comments)
https://review.coreboot.org/c/em100/+/36943/13/em100.c File em100.c:
https://review.coreboot.org/c/em100/+/36943/13/em100.c@656 PS13, Line 656: static int list_chips_entry(char *name __unused, TFILE *file, void *data __unused, int ok __unused)
Sanity check: the return value is always the same. […]
It is intended, 0 means continue != 0 means break after this. We want to iterate through the whole list of chips.
But I rewrote this function to only have one return statement and have the printf call in a reversed if block instead.
https://review.coreboot.org/c/em100/+/36943/13/em100.c@693 PS13, Line 693: dcfg
Sanity check: Is it needed to call `tar_close(dcfg)` before returning?
Done
https://review.coreboot.org/c/em100/+/36943/13/em100.c@989 PS13, Line 989: const
Why is this const if its value gets modified by `get_chip_type()`?
Good point.
https://review.coreboot.org/c/em100/+/36943/13/tar.c File tar.c:
https://review.coreboot.org/c/em100/+/36943/13/tar.c@87 PS13, Line 87: if(!ok)
missing space
Done
https://review.coreboot.org/c/em100/+/36943/13/tar.c@121 PS13, Line 121: if(!ok)
missing space
Done
Angel Pons has posted comments on this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Patch Set 14: Code-Review+2
(1 comment)
https://review.coreboot.org/c/em100/+/36943/13/em100.c File em100.c:
https://review.coreboot.org/c/em100/+/36943/13/em100.c@656 PS13, Line 656: static int list_chips_entry(char *name __unused, TFILE *file, void *data __unused, int ok __unused)
It is intended, 0 means continue != 0 means break after this. […]
Ack
Stefan Reinauer has submitted this change. ( https://review.coreboot.org/c/em100/+/36943 )
Change subject: Use binaries from Windows installer directly ......................................................................
Use binaries from Windows installer directly
Find configs.tar.xz in $HOME/.em100/ or $EM100_HOME and load chip descriptions from there instead of bringing the static array of all chips along with the binary. This allows updating the chip database from the Windows installer without recompiling the em100 tool.
Change-Id: I8c360e96ce42fd78141a1564976454711e20f527 Signed-off-by: Stefan Reinauer stefan.reinauer@coreboot.org Reviewed-on: https://review.coreboot.org/c/em100/+/36943 Tested-by: build bot (Jenkins) no-reply@coreboot.org Reviewed-by: Angel Pons th3fanbus@gmail.com --- M Makefile A chips.c M em100.c M em100.h A tar.c 5 files changed, 775 insertions(+), 46 deletions(-)
Approvals: build bot (Jenkins): Verified Angel Pons: Looks good to me, approved
diff --git a/Makefile b/Makefile index 698920b..bd20b47 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ CFLAGS += -Wall -Wundef -Wstrict-prototypes -Wmissing-prototypes CFLAGS += -Wwrite-strings -Wredundant-decls -Wstrict-aliasing -Wshadow -Wextra CFLAGS += -Wno-unused-but-set-variable +CFLAGS += -DXZ_USE_CRC64 -DXZ_DEC_ANY_CHECK -Ixz # Remove after fixing CFLAGS += -Wno-sign-compare -Wno-discarded-qualifiers
@@ -38,7 +39,9 @@ CC ?= gcc PKG_CONFIG ?= pkg-config
+XZ = xz/xz_crc32.c xz/xz_crc64.c xz/xz_dec_bcj.c xz/xz_dec_lzma2.c xz/xz_dec_stream.c SOURCES = em100.c firmware.c fpga.c hexdump.c sdram.c spi.c system.c trace.c usb.c +SOURCES += chips.c tar.c $(XZ) OBJECTS = $(SOURCES:.c=.o)
all: dep em100 diff --git a/chips.c b/chips.c new file mode 100644 index 0000000..acd90e1 --- /dev/null +++ b/chips.c @@ -0,0 +1,329 @@ +/* + * Copyright 2012 Google Inc. + * + * 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; version 2 of the License. + * + * 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. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdint.h> +#ifdef __APPLE__ +#include <libkern/OSByteOrder.h> +#define bswap_16(x) OSSwapInt16(x) +#define bswap_32(x) OSSwapInt32(x) +#include <architecture/byte_order.h> + #if BYTE_ORDER == LITTLE_ENDIAN + #define le32toh(x) (x) + #define le16toh(x) (x) + #define htobe16(x) bswap_16(x) + #else + #define le32toh(x) bswap_32(x) + #define le16toh(x) bswap_16(x) + #define htobe16(x) (x) + #endif +#else +#include <endian.h> +#endif + +#include "em100.h" + +#define DEDIPROG_CFG_PRO_MAX_ENTRIES 212 + +#define DEDIPROG_CFG_PRO_SIZE 176 +#define DEDIPROG_CFG_PRO_SIZE_SFDP 256 +#define DEDIPROG_CFG_PRO_SIZE_SRST 144 + +#define DEDIPROG_CFG_MAGIC 0x67666344 /* 'Dcfg' */ +#define DEDIPROG_SFDP_MAGIC 0x50444653 /* 'SFDP' */ +#define DEDIPROG_SRST_MAGIC 0x54535253 /* 'SRST' */ +#define DEDIPROG_PROT_MAGIC 0x544f5250 /* 'PROT' */ + +#define INIT_SEQUENCE_REIGSTER_OFFSET_0 0x2300 +#define INIT_SEQUENCE_REIGSTER_OFFSET_1 0x1100 + +/* Init sequence and file format: + * + * All v1.1 dediprog configuration files are 176 bytes and all values are + * encoded as little endian format. + + * At offset init_offset the init sequence consists of init entries that are + * sent to endpoint 1. There are 2 sets of entries separated by a 32-bit + * terminator of 0xffffffff. Each entry consists of a value and register offset. + * The first set of entries have a base register address of 0x2300 while the + * the second set of entries have a base register address of 0x1100. Each entry + * is sent to the device as <register> <value>, however the data is sent in + * big endian format. Additionally, each entry is sent as a 16-byte transfer + * with the remaining bytes all 0's. + * + * Configuration files that are >= 436 bytes contain SFDP data, separated by + * the magic value 'SFDP' while those that are 584 bytes contain SRST data + * separated by the magic value 'SRST' and containing 0 or 3 entries followed + * by PROT data in the rest of the buffer. Unfortunately there does not seem + * to be any change in the version fields and these are still reported as 1.1. + */ + + +struct dediprog_cfg_hdr { + uint32_t magic; + uint16_t ver_min; + uint16_t ver_maj; + uint32_t init_offset; + uint32_t chip_size; + uint32_t vendor_name_offset; + uint32_t chip_name_offset; + uint32_t unknown_offset[2]; +} __attribute__((packed)); + +struct dediprog_cfg_pro { + struct dediprog_cfg_hdr hdr; + uint8_t payload[DEDIPROG_CFG_PRO_SIZE-sizeof(struct dediprog_cfg_hdr)]; +} __attribute__((packed)); + + +struct dediprog_cfg_init_entry { + uint16_t value; + uint16_t reg; +} __attribute__((packed)); + +unsigned char cfg_buffer[DEDIPROG_CFG_PRO_SIZE]; + +static int parse_and_output_config(struct dediprog_cfg_pro *cfg, chipdesc *chip) +{ + struct dediprog_cfg_init_entry *entry, *end; + struct dediprog_cfg_hdr *hdr; + const char *vendor, *chip_name; + uint16_t reg_offset; + int entries = 0; + + hdr = &cfg->hdr; + + /* The magic number is actually string, but it can be converted to + * a host ordered 32-bit number. */ + hdr->magic= le32toh(hdr->magic); + + if (hdr->magic != DEDIPROG_CFG_MAGIC) { + fprintf(stderr, "Invalid magic number: 0x%x\n", hdr->magic); + return -1; + } + + /* Convert all header values from little endian to host byte order. */ + hdr->ver_min = le16toh(hdr->ver_min); + hdr->ver_maj = le16toh(hdr->ver_maj); + hdr->init_offset = le32toh(hdr->init_offset); + hdr->chip_size = le32toh(hdr->chip_size); + hdr->vendor_name_offset = le32toh(hdr->vendor_name_offset); + hdr->chip_name_offset = le32toh(hdr->chip_name_offset); + + if (hdr->ver_maj != 1 && hdr->ver_min != 1) { + fprintf(stderr, "Invalid version number: %d.%d\n", hdr->ver_maj, + hdr->ver_min); + return -1; + } + + /* Adjust the offsets to be into the payload of the config file. */ + hdr->init_offset -= sizeof(*hdr); + hdr->vendor_name_offset -= sizeof(*hdr); + hdr->chip_name_offset -= sizeof(*hdr); + + vendor = (void *)&cfg->payload[hdr->vendor_name_offset]; + chip_name = (void *)&cfg->payload[hdr->chip_name_offset]; + + /* Since configs.tar is resident, we don't have to malloc */ + chip->vendor = (const char *)vendor; + chip->name = (const char *)chip_name; + chip->size = hdr->chip_size; + +#ifdef DEBUG + printf("%s %s (%d kB)\n", + vendor, chip_name, hdr->chip_size/1024); +#endif + + entry = (void *)&cfg->payload[hdr->init_offset]; + end = (void *)&cfg[1]; /* 1 past the last entry */ + + reg_offset = INIT_SEQUENCE_REIGSTER_OFFSET_0; + + for (; entry != end; entry++) { + uint8_t *reg, *value; + + /* Convert from little endian to host format. */ + entry->value = le16toh(entry->value); + entry->reg = le16toh(entry->reg); + + if (entry->value == 0xffff && entry->reg == 0xffff) { + reg_offset = INIT_SEQUENCE_REIGSTER_OFFSET_1; + continue; + } + + entry->reg += reg_offset; + + /* Convert from host to big endian format. */ + entry->value = htobe16(entry->value); + entry->reg = htobe16(entry->reg); + + value = (void *)&entry->value; + reg = (void *)&entry->reg; + + chip->init[entries][0] = reg[0]; + chip->init[entries][1] = reg[1]; + chip->init[entries][2] = value[0]; + chip->init[entries][3] = value[1]; + ++entries; + } + + return entries; +} + +static int parse_and_output_sfdp(chipdesc *chip, void **ptr, int *length, int entries) +{ + int i, len = 0; + unsigned char *sfdp_buffer = (unsigned char *)*ptr; + + if (*length < DEDIPROG_CFG_PRO_SIZE_SFDP) { + fprintf(stderr, "Error reading SFDP\n"); + return -1; + } + + chip->init[entries][0] = 0x23; + chip->init[entries][1] = 0xc9; + chip->init[entries][2] = 0x00; + chip->init[entries][3] = 0x01; + + len++; + + for (i = 0; i < DEDIPROG_CFG_PRO_SIZE_SFDP; i+=2) { + chip->init[entries+len][0] = 0x23; + chip->init[entries+len][1] = 0xc1; + chip->init[entries+len][2] = sfdp_buffer[i+1]; + chip->init[entries+len][3] = sfdp_buffer[i]; + len++; + } + + *ptr += DEDIPROG_CFG_PRO_SIZE_SFDP; + *length -= DEDIPROG_CFG_PRO_SIZE_SFDP; + + return len; +} + +static int parse_and_output_srst(chipdesc *chip, void **ptr, int *length, int entries) +{ + int i, len = 0; + uint32_t magic; + unsigned char *srst_buffer = (unsigned char *)*ptr; + + if (*length < DEDIPROG_CFG_PRO_SIZE_SRST) { + fprintf(stderr, "Error reading SRST\n"); + return -1; + } + + /* SRST has 0 or 3 entries before PROT */ + memcpy(&magic, &srst_buffer[0], sizeof(magic)); + + if (magic != DEDIPROG_PROT_MAGIC) { + int j; + + for (j = 0; j < 3; j++) { + chip->init[entries+len][0] = 0x23; + chip->init[entries+len][1] = srst_buffer[j*4+2]; + chip->init[entries+len][2] = srst_buffer[j*4+1]; + chip->init[entries+len][3] = srst_buffer[j*4]; + len++; + } + + /* Start after SFDP data and PROT magic */ + i = 16; + } else { + /* Start after PROT magic */ + i = 4; + } + + chip->init[entries+len][0] = 0x23; + chip->init[entries+len][1] = 0xc4; + chip->init[entries+len][2] = 0x00; + chip->init[entries+len][3] = 0x01; + len++; + + for (; i < DEDIPROG_CFG_PRO_SIZE_SRST; i+=2) { + chip->init[entries+len][0] = 0x23; + chip->init[entries+len][1] = 0xc5; + chip->init[entries+len][2] = srst_buffer[i+1]; + chip->init[entries+len][3] = srst_buffer[i]; + len++; + } + + *ptr += DEDIPROG_CFG_PRO_SIZE_SRST; + *length -= DEDIPROG_CFG_PRO_SIZE_SRST; + + return len; +} + +int parse_dcfg(chipdesc *chip, TFILE *dcfg) +{ + struct dediprog_cfg_pro *cfg; + int init_len = 0; + uint32_t magic; + + void *ptr = (void *)dcfg->address; + int length = dcfg->length; + + if (length < sizeof(cfg_buffer)) { + /* Not a config file */ + return 1; + } + cfg = (struct dediprog_cfg_pro *)ptr; + + init_len = parse_and_output_config(cfg, chip); + if (init_len < 0) { + fprintf(stderr, "Error parsing Dcfg\n"); + return 1; + } + + ptr += DEDIPROG_CFG_PRO_SIZE; + length -= DEDIPROG_CFG_PRO_SIZE; + + /* Handle any extra data */ + while (length) { + int ret = 0; + + magic = *(uint32_t *)ptr; + ptr+=sizeof(uint32_t); + length-=sizeof(uint32_t); + + switch (magic) { + case DEDIPROG_SFDP_MAGIC: + ret = parse_and_output_sfdp(chip, &ptr, &length, init_len); + break; + case DEDIPROG_SRST_MAGIC: + ret = parse_and_output_srst(chip, &ptr, &length, init_len); + break; + default: + fprintf(stderr, "Unknown magic: 0x%08x\n", magic); + break; + } + + if (ret < 0) { + fprintf(stderr, "FAILED.\n"); + return 1; + } + init_len += ret; + } + + chip->init_len = init_len; + + return 0; +} diff --git a/em100.c b/em100.c index b389dc8..8596edb 100644 --- a/em100.c +++ b/em100.c @@ -22,10 +22,15 @@ #include <signal.h> #include <getopt.h> #include <unistd.h> +#include <dirent.h> +#include <errno.h> +#include <sys/stat.h> +#include <wordexp.h> + #include "em100.h"
-/* SPI flash chips parameters definition */ -#include "em100pro_chips.h" +TFILE *configs; +char *database_version;
volatile int do_exit_flag = 0;
@@ -517,7 +522,7 @@ int fpga_voltage, chip_voltage = 0; int req_voltage = 0;
- printf("Sending flash chip configuration\n"); + printf("Configuring SPI flash chip emulation.\n");
memset(cmd, 0, 16);
@@ -597,6 +602,31 @@ return 1; }
+typedef struct { + uint16_t venid; + uint16_t devid; + int found; + chipdesc chip; +} vendev_t; + +static int get_chip_type_entry(char *name __unused, TFILE *dcfg, void *data, int ok __unused) +{ + uint16_t comp; + chipdesc chip; + + vendev_t *v = (vendev_t *)data; + + parse_dcfg(&chip, dcfg); + + if (get_chip_init_val(&chip, 0x23, FPGA_REG_DEVID, &comp) || v->devid != comp) + return 0; + if (get_chip_init_val(&chip, 0x23, FPGA_REG_VENDID, &comp) || v->venid != comp) + return 0; + v->found = 1; + v->chip = chip; + return 1; +} + /** * Tries to identify the currently emulated SPI flash by looking at * known registers in the FPGA and matches those bits with the @@ -604,62 +634,109 @@ * * Returns 0 on success. */ -static int get_chip_type(struct em100 *em100, const chipdesc **out) +static int get_chip_type(struct em100 *em100, chipdesc *out) { - const chipdesc *chip; - uint16_t venid; - uint16_t devid; + vendev_t v;
/* Read manufacturer and vendor id from FPGA */ - if (!read_fpga_register(em100, FPGA_REG_VENDID, &venid)) + if (!read_fpga_register(em100, FPGA_REG_VENDID, &v.venid)) return 1; - if (!read_fpga_register(em100, FPGA_REG_DEVID, &devid)) + if (!read_fpga_register(em100, FPGA_REG_DEVID, &v.devid)) return 1;
- for (chip = chips; chip->name != NULL; chip++) { - uint16_t comp; - - if (get_chip_init_val(chip, 0x23, FPGA_REG_DEVID, &comp) || devid != comp) - continue; - if (get_chip_init_val(chip, 0x23, FPGA_REG_VENDID, &comp) || venid != comp) - continue; - - break; - } - - if (!chip->name) + tar_for_each(configs, get_chip_type_entry, (void *)&v); + if (!v.found) return 1;
- *out = chip; + *out = v.chip; + + return 0; +} + +static int list_chips_entry(char *name __unused, TFILE *file, void *data __unused, int ok __unused) +{ + static chipdesc chip; + /* Is the file a dcfg file? Then print the name, otherwise skip. */ + + if (!parse_dcfg(&chip, file)) + printf(" • %s %s\n", chip.vendor, chip.name);
return 0; }
static chipdesc *setup_chips(const char *desiredchip) { - const chipdesc *chip = chips; + static chipdesc chip; + configs = tar_load_compressed(get_em100_file("configs.tar.xz")); + if (!configs) { + printf("Can't find chip configs in $EM100_HOME/configs.tar.xz.\n"); + return NULL; + } + + TFILE *version = tar_find(configs,"configs/VERSION", 1); + if (!version) { + printf("Can't find VERSION of chip configs.\n"); + return NULL; + } + database_version = (char *)version->address; + tar_close(version); + if (desiredchip) { - do { - if (strcasecmp(desiredchip, chip->name) == 0) { - printf("will emulate '%s'\n", chip->name); - break; - } - } while ((++chip)->name); - - if (chip->name == NULL) { - printf("Supported chips:\n"); - chip = chips; - do { - printf("%s ", chip->name); - } while ((++chip)->name); - printf("\n\nCould not find emulation for '%s'.\n", + char chipname[256]; + sprintf(chipname, "configs/%s.cfg", desiredchip); + TFILE *dcfg = tar_find(configs, chipname, 0); + if (!dcfg) { + printf("Supported chips:\n\n"); + tar_for_each(configs, list_chips_entry, NULL); + printf("\nCould not find a chip matching '%s' to be emulated.\n", desiredchip); - return NULL; } - + parse_dcfg(&chip, dcfg); + tar_close(dcfg); + return &chip; } - return chip; + return NULL; +} + +static char *get_em100_home(void) +{ + static char directory[FILENAME_BUFFER_SIZE] = "\0"; + + if (directory[0] != 0) + return directory; + + /* find out file */ + wordexp_t p; + char *em100_home = getenv("EM100_HOME"); + if (em100_home) + wordexp("$EM100_HOME/", &p, 0); + else + wordexp("$HOME/.em100/", &p, 0); + + strncpy(directory, p.we_wordv[0], FILENAME_BUFFER_SIZE - 1); + wordfree(&p); + + DIR *dir = opendir(directory); + if (dir) { + // success + } else if (errno == ENOENT) { + mkdir(directory, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + } else { + perror("EM100_HOME inaccessible"); + directory[0]=0; + return NULL; + } + + return directory; +} + +char *get_em100_file(char *name) +{ + char file[FILENAME_BUFFER_SIZE]; + strncpy(file, get_em100_home(), FILENAME_BUFFER_SIZE); + strncat(file, name, FILENAME_BUFFER_SIZE - strlen(file) - 1); + return strdup(file); }
static const struct option longopts[] = { @@ -813,7 +890,7 @@ }
const chipdesc *chip = setup_chips(desiredchip); - if (!chip) + if (desiredchip && !chip) return 1;
printf("MCU version: %d.%02d\n", em100.mcu >> 8, em100.mcu & 0xff); @@ -842,7 +919,7 @@ printf("Serial number: EM%06d\n", em100.serialno); else printf("Serial number: N.A.\n"); - printf("SPI flash database: %s\n", VERSION); + printf("SPI flash database: %s\n", database_version); get_current_state(&em100); get_current_pin_state(&em100); printf("\n"); @@ -890,7 +967,7 @@ printf("Failed configuring chip type.\n"); return 0; } - printf("Chip set to %s\n", desiredchip); + printf("Chip set to %s %s.\n", chip->vendor, chip->name); }
if (voltage) { @@ -912,11 +989,11 @@
if (!desiredchip) { /* Read configured SPI emulation from EM100 */ - const chipdesc *emulated_chip; + chipdesc emulated_chip;
if (!get_chip_type(&em100, &emulated_chip)) { - printf("Configured to emulate %s\n", emulated_chip->name); - maxlen = emulated_chip->size; + printf("Configured to emulate %dkB chip\n", emulated_chip.size / 1024); + maxlen = emulated_chip.size; } } else { maxlen = chip->size; diff --git a/em100.h b/em100.h index 72518d1..f126b7d 100644 --- a/em100.h +++ b/em100.h @@ -32,6 +32,16 @@ uint8_t hwversion; };
+#define NUM_INIT_ENTRIES 212 +#define BYTES_PER_INIT_ENTRY 4 +typedef struct { + const char *vendor; + const char *name; + unsigned int size; + uint8_t init[NUM_INIT_ENTRIES][BYTES_PER_INIT_ENTRY]; + int init_len; +} chipdesc; + /* Hardware versions */ #define HWVERSION_EM100PRO 4 #define HWVERSION_EM100PRO_G2 6 @@ -165,8 +175,26 @@ int read_spi_terminal(struct em100 *em100, int print_counter); int init_spi_terminal(struct em100 *em100);
+/* Archive handling */ +typedef struct { + unsigned char *address; + size_t length; + int alloc; +} TFILE; +TFILE *tar_find(TFILE *tfile, char *name, int casesensitive); +TFILE *tar_load_compressed(char *filename); +int tar_for_each(TFILE *tfile, int (*run)(char *, TFILE *, void *, int), void *data); +int tar_close(TFILE *tfile); +int tar_ls(TFILE *tfile); +int test_tar(void); + /* Misc. */
#define MB * 1024 * 1024 +#define FILENAME_BUFFER_SIZE 1024 +char *get_em100_file(char *name); + +/* Chips */ +int parse_dcfg(chipdesc *chip, TFILE *dcfg);
#endif diff --git a/tar.c b/tar.c new file mode 100644 index 0000000..e8d3664 --- /dev/null +++ b/tar.c @@ -0,0 +1,292 @@ +/* + * Copyright 2019 Google LLC + * + * 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; version 2 of the License. + * + * 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. + */ + +#define _GNU_SOURCE +#include <stddef.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "em100.h" +#include "xz.h" + +#define ROUND_UP(n, inc) (n + (inc - n % inc) % inc) + +typedef struct { + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char mtime[12]; + char checksum[8]; + char type; + char linkname[100]; + char magic[6]; + char version[2]; + char uname[32]; + char gname[32]; + char devmajor[8]; + char devminor[8]; + char prefix[155]; + char padding[12]; +} __packed tar_header_t; + +static unsigned int checksum(tar_header_t *file) +{ + int i, chk_off = offsetof(tar_header_t, checksum); + unsigned char *raw = (unsigned char *)file; + unsigned int chksum = 256; + + for (i = 0; i < sizeof(tar_header_t); i++) { + if (i >= chk_off && i < chk_off + 8) + continue; + chksum += raw[i]; + } + return chksum; +} + +int tar_for_each(TFILE *tfile, int (*run)(char *, TFILE *, void *, int), void *data) +{ + size_t i = 0; + + while (i < tfile->length) { + tar_header_t *f = (tar_header_t *)(tfile->address + i); + /* null header at end of tar */ + if (f->name[0] == 0) + break; + + unsigned int size = strtol(f->size, NULL, 8); + unsigned int cksum = strtol(f->checksum, NULL, 8); + unsigned int ok = (checksum(f) == cksum); + + if (f->type == '0') { + TFILE s; + s.address = tfile->address + i + sizeof(tar_header_t); + s.length = size; + s.alloc = 0; + + if ((*run)(f->name, &s, data, ok)) + break; + } + + if (!ok) + break; + i += sizeof(tar_header_t) + ROUND_UP(size, 512); + } + + return 0; +} + +static int tar_ls_entry(char *name, TFILE *file __unused, void *data __unused, int ok) +{ + printf("%s %s\n", name, ok?"✔":"✘"); + return 0; +} + +int tar_ls(TFILE *tfile) +{ + tar_for_each(tfile, tar_ls_entry, NULL); + return 0; +} + +TFILE *tar_find(TFILE *tfile, char *name, int casesensitive) +{ + size_t i = 0; + TFILE *ret; + + while (i < tfile->length) { + tar_header_t *f = (tar_header_t *)(tfile->address + i); + if (f->name[0] == 0) /* null header at end of tar */ + break; + + unsigned int size = strtol(f->size, NULL, 8); + unsigned int cksum = strtol(f->checksum, NULL, 8); + unsigned int ok = (checksum(f) == cksum); + + if (!ok) + break; + + int compare = casesensitive ? strncmp(name, f->name, 100) : + strncasecmp(name, f->name, 100); + if (!compare && f->type == '0') { + ret = (TFILE *)malloc(sizeof(TFILE)); + if (!ret) { + perror("Out of memory.\n"); + return NULL; + } + + ret->address = tfile->address + i + sizeof(tar_header_t); + ret->length = size; + ret->alloc = 0; + + return ret; + } + i += sizeof(tar_header_t) + ROUND_UP(size, 512); + } + + return NULL; +} + +/* Finding the uncompressed size of an archive should really be part + * of the xz API. + */ +static uint32_t decode_vli(unsigned char **streamptr) +{ + unsigned char *stream = *streamptr; + uint32_t val = 0; + int pos = 0; + + val = *stream & 0x7f; + do { + pos += 7; + stream++; + val |= ((uint32_t)*stream & 0x7f) << pos; + } while (stream[0] & 0x80); + *streamptr = stream+1; + + return val; +} + +static uint32_t uncompressed_size(unsigned char *stream, size_t length) +{ + if (stream[length-2] != 0x59 || stream[length-1] != 0x5a) { + printf("Bad stream footer.\n"); + return 0; + } + unsigned char *bytes = stream + length - 8; + uint32_t backward_size = + bytes[0] | (bytes[1]<<8) | (bytes[2]<<16) | (bytes[3]<<24); + backward_size = (backward_size + 1) << 2; + bytes = stream + length - 12 /* stream footer */ - backward_size; + if (bytes[0] != 0x00) { + printf("Bad index indicator.\n"); + return 0; + } + if (bytes[1] != 0x01) { + printf("More than one index. I'm confused.\n"); + return 0; + } + bytes += 2; + + /* skip unpadded size */ + decode_vli(&bytes); + return decode_vli(&bytes); + + return 0; +} + +TFILE *tar_load_compressed(char *filename) +{ + FILE *f; + long cfsize, fsize; + unsigned char *cfw, *fw; + + /* Load our file into memory */ + + f = fopen(filename, "rb"); + if (!f) { + perror(filename); + return NULL; + } + + fseek(f, 0, SEEK_END); + cfsize = ftell(f); + if (cfsize < 0) { + perror(filename); + fclose(f); + return NULL; + } + fseek(f, 0, SEEK_SET); + + cfw = malloc(cfsize); + if (!cfw) { + printf("Out of memory.\n"); + fclose(f); + return NULL; + } + if (fread(cfw, cfsize, 1, f) != 1) { + perror(filename); + fclose(f); + free(cfw); + return NULL; + } + fclose(f); + + fsize = uncompressed_size(cfw, cfsize); + fw = malloc(fsize); + if (!fw) { + printf("Out of memory.\n"); + free(cfw); + return NULL; + } + + /* Decompress xz */ + struct xz_buf b; + struct xz_dec *s; + enum xz_ret ret; + + xz_crc32_init(); +#ifdef XZ_USE_CRC64 + xz_crc64_init(); +#endif + s = xz_dec_init(XZ_SINGLE, 0); + if (s == NULL) { + printf("Decompression init failed.\n"); + free(cfw); + free(fw); + return NULL; + } + + b.in = cfw; + b.in_pos = 0; + b.in_size = cfsize; + b.out = fw; + b.out_pos = 0; + b.out_size = fsize; + + ret = xz_dec_run(s, &b); + if (ret != XZ_STREAM_END) { + printf("Decompression failed.\n"); + free(cfw); + free(fw); + return NULL; + } + free(cfw); + + /* Prepare answer */ + TFILE *tfile = malloc(sizeof(TFILE)); + if (tfile == NULL) { + printf("Out of memory.\n"); + free(fw); + return NULL; + } + tfile->address = fw; + tfile->length = fsize; + tfile->alloc = 1; + + return tfile; +} + +int tar_close(TFILE *tfile) +{ + if (tfile->alloc) { + free(tfile->address); + } + free(tfile); + return 0; +}