Implement version information storage and retrieval for the bootrom and the osimage.

Use perl to create the version information (thereby re-creating the perl dependency and adding an svn dependency) but fall back in case of missing perl or svn
This commit is contained in:
henryk@ploetzli.ch 2009-08-28 06:40:44 +00:00
commit 8a6aec16d8
13 changed files with 171 additions and 13 deletions

View file

@ -13,6 +13,7 @@ THUMBSRC = start.c \
lfops.c \
iso15693.c \
util.c \
version.c \
usb.c
# These are to be compiled in ARM mode
@ -43,6 +44,7 @@ clean:
$(DELETE) $(OBJDIR)$(PATHSEP)*.s19
$(DELETE) $(OBJDIR)$(PATHSEP)*.map
$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(DELETE) version.c
.PHONY: all clean help
help:

View file

@ -236,10 +236,28 @@ void ReadMem(int addr)
DbpIntegers(0, data[i], data[i+1]);
}
/* osimage version information is linked in */
extern struct version_information version_information;
void SendVersion(void)
{
char temp[48]; /* Limited data payload in USB packets */
DbpString("Prox/RFID mark3 RFID instrument");
/* Try to find the bootrom version information. For the time being, expect
* to find a pointer at address 0x1001fc, perform slight sanity checks on
* the pointer, then use it.
*/
void *bootrom_version = *(void**)0x1001fc;
if( bootrom_version < (void*)0x100000 || bootrom_version > (void*)0x101000 ) {
DbpString("bootrom version information appears invalid");
} else {
FormatVersionInformation(temp, sizeof(temp), "bootrom: ", bootrom_version);
DbpString(temp);
}
FormatVersionInformation(temp, sizeof(temp), "os: ", &version_information);
DbpString(temp);
FpgaGatherVersion(temp, sizeof(temp));
DbpString(temp);
}

View file

@ -112,5 +112,6 @@ void LED(int led, int ms);
void LEDsoff();
int BUTTON_CLICKED(int ms);
int BUTTON_HELD(int ms);
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);
#endif

View file

@ -12,6 +12,7 @@ SECTIONS
*(.text.*)
*(.glue_7)
*(.glue_7t)
*(.version_information)
} >osimage
.rodata : {
*(.rodata)

View file

@ -235,3 +235,37 @@ void SpinDelay(int ms)
// convert to uS and call microsecond delay function
SpinDelayUs(ms*1000);
}
/* Similar to FpgaGatherVersion this formats stored version information
* into a string representation. It takes a pointer to the struct version_information,
* verifies the magic properties, then stores a formatted string, prefixed by
* prefix in dst.
*/
void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information)
{
struct version_information *v = (struct version_information*)version_information;
dst[0] = 0;
strncat(dst, prefix, len);
if(v->magic != VERSION_INFORMATION_MAGIC) {
strncat(dst, "Missing/Invalid version information", len);
return;
}
if(v->versionversion != 1) {
strncat(dst, "Version information not understood", len);
return;
}
if(!v->present) {
strncat(dst, "Version information not available", len);
return;
}
strncat(dst, v->svnversion, len);
if(v->clean == 0) {
strncat(dst, "-unclean", len);
} else if(v->clean == 2) {
strncat(dst, "-suspect", len);
}
strncat(dst, " ", len);
strncat(dst, v->buildtime, len);
}

View file

@ -2,7 +2,7 @@
# DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code
ARMSRC = fromflash.c
THUMBSRC = usb.c bootrom.c
THUMBSRC = usb.c version.c bootrom.c
ASMSRC = ram-reset.s flash-reset.s
# Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC
@ -19,8 +19,9 @@ clean:
$(DELETE) $(OBJDIR)$(PATHSEP)*.s19
$(DELETE) $(OBJDIR)$(PATHSEP)*.map
$(DELETE) $(OBJDIR)$(PATHSEP)*.d
$(DELETE) version.c
.PHONY: all clean help
.PHONY: all clean help
help:
@echo Multi-OS Makefile, you are running on $(DETECTED_OS)
@echo Possible targets:

View file

@ -1,6 +1,6 @@
#include <proxmark3.h>
void __attribute__((section("bootphase1"))) CopyBootToRAM(void)
void __attribute__((section(".bootphase1"))) CopyBootToRAM(void)
{
int i;

View file

@ -8,6 +8,18 @@ SECTIONS
bootphase1 : {
*(.startup)
*(.bootphase1)
/* It seems to be impossible to flush align a section at the
end of a memory segment. Instead, we'll put the version_information
wherever the linker wants it, and then put a pointer to the start
of the version information at the end of the section.
-- Henryk Plötz <henryk@ploetzli.ch> 2009-08-28 */
_version_information_start = .;
*(.version_information);
. = LENGTH(bootphase1) - 0x4; /* Skip ahead to the end */
LONG(_version_information_start)
} >bootphase1
bootphase2 : {

View file

@ -20,6 +20,7 @@ ifeq ($(UNAME), Linux)
# Linux. (Todo: Add MacOS X if appropriate)
DELETE=rm -rf
MOVE=mv
COPY=cp
PATHSEP=/
DETECTED_OS=Linux
# You may/should set this in your environment
@ -31,6 +32,7 @@ else
# Assume that we are running on Windows.
DELETE=del /q
MOVE=ren
COPY=copy
PATHSEP=\\#
ARMLIB ?= ../../devkitARM/lib/gcc/arm-elf/4.1.0/interwork
DETECTED_OS=Windows
@ -77,6 +79,11 @@ $(OBJDIR)/%.s19: $(OBJDIR)/%.elf
--change-section-address .text-0x100000 \
--change-section-address .rodata-0x100000 $^ $@
# version.c should be remade on every compilation
.PHONY: version.c
version.c: default_version.c
perl ../tools/mkversion.pl .. > $@ || $(COPY) $^ $@
# Automatic dependency generation
DEPENDENCY_FILES = $(patsubst %.c,$(OBJDIR)/%.d,$(notdir $(THUMBSRC))) \
$(patsubst %.c,$(OBJDIR)/%.d,$(notdir $(ARMSRC))) \

9
common/default_version.c Normal file
View file

@ -0,0 +1,9 @@
#include <proxmark3.h>
/* This is the default version.c file that Makefile.common falls back to if perl is not available */
struct version_information __attribute__((section(".version_information"))) version_information = {
VERSION_INFORMATION_MAGIC,
1, /* version version 1 */
0, /* version information not present */
2, /* cleanliness couldn't be determined */
/* Remaining fields: zero */
};

View file

@ -1,10 +0,0 @@
#define VERSION "$Id $"
static const struct __attribute__((packed)) {
const char string[48];
unsigned int length;
unsigned int magic;
} version __attribute__((unused,section("versioninformation"))) = {
VERSION,
sizeof(VERSION),
0x48151623,
};

View file

@ -60,4 +60,14 @@ void UsbStart(void);
// if data are available.
void UsbPacketReceived(BYTE *packet, int len);
#define VERSION_INFORMATION_MAGIC 0x56334d50
struct version_information {
int magic; /* Magic sequence to identify this as a correct version information structure. Must be VERSION_INFORMATION_MAGIC */
char versionversion; /* Must be 1 */
char present; /* 1 if the version information could be created at compile time, otherwise 0 and the remaining fields (except for magic) are empty */
char clean; /* 1: Tree was clean, no local changes. 0: Tree was unclean. 2: Couldn't be determined */
char svnversion[9]; /* String with the SVN revision */
char buildtime[30]; /* string with the build time */
} __attribute__((packed));
#endif

73
tools/mkversion.pl Normal file
View file

@ -0,0 +1,73 @@
#!/usr/bin/perl
# Output a version.c file that includes information about the current build
# Normally a couple of lines of bash would be enough (see openpcd project, original firmware by Harald Welte and Milosch Meriac)
# but this will, at least in theory, also work on Windows with our current compile environment.
# -- Henryk Plötz <henryk@ploetzli.ch> 2009-09-28
use strict;
my $main_dir = shift;
# Clear environment locale so that svn will not use localized strings
$ENV{'LC_ALL'} = "C";
$ENV{'LANG'} = "C";
my $svnversion = 0;
my $present = 0;
my $clean = 2;
my @compiletime = gmtime();
# Strategy one: call svn info and extract last changed revision, call svn status and look for ^M
if(open(SVNINFO, "svn info $main_dir|")) {
while(<SVNINFO>) {
if (/^Last Changed Rev: (.*)/) {
$present = 1;
$svnversion = $1;
## last; # Do not abort here, since SVN tends to complain about a Broken pipe
}
}
close(SVNINFO);
if(open(SVNSTATUS, "svn status $main_dir|")) {
$clean = 1;
while(<SVNSTATUS>) {
if(/^M/) {
$clean = 0;
## last;
}
}
close(SVNINFO);
}
} else {
# Strategy two: look for .svn/entries. The third line should be "dir", the fourth line should contain the current
# revision.
if(open(ENTRIES, "$main_dir/.svn/entries")) {
my $i = 1;
while(<ENTRIES>) {
last if($i == 3 and !/^dir/);
if($i == 4 and /^([0-9]*)/) {
$present = 1;
$svnversion = $1;
}
$i++;
}
}
}
$compiletime[4] += 1;
$compiletime[5] += 1900;
my $ctime = sprintf("%6\$04i-%5\$02i-%4\$02i %3\$02i:%2\$02i:%1\$02i", @compiletime);
print <<EOF
#include <proxmark3.h>
/* Generated file, do not edit */
struct version_information __attribute__((section(".version_information"))) version_information = {
VERSION_INFORMATION_MAGIC,
1,
$present,
$clean,
"svn $svnversion",
"$ctime",
};
EOF