Implement version information storage and retrieval for the bootrom and the osimage.
authorhenryk@ploetzli.ch <henryk@ploetzli.ch@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Fri, 28 Aug 2009 06:40:44 +0000 (06:40 +0000)
committerhenryk@ploetzli.ch <henryk@ploetzli.ch@ef4ab9da-24cd-11de-8aaa-f3a34680c41f>
Fri, 28 Aug 2009 06:40:44 +0000 (06:40 +0000)
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

13 files changed:
armsrc/Makefile
armsrc/appmain.c
armsrc/apps.h
armsrc/ldscript
armsrc/util.c
bootrom/Makefile
bootrom/fromflash.c
bootrom/ldscript-flash
common/Makefile.common
common/default_version.c [new file with mode: 0644]
common/version.c [deleted file]
include/proxmark3.h
tools/mkversion.pl [new file with mode: 0644]

index 5ed76ccc36f7a73c9f104d806a211a43b0ce25b6..13e43ba90337465b421e95b5f25d2ba238cef080 100644 (file)
@@ -13,6 +13,7 @@ THUMBSRC = start.c \
        lfops.c \\r
        iso15693.c \\r
        util.c \\r
+       version.c \\r
        usb.c\r
 \r
 # These are to be compiled in ARM mode\r
@@ -43,6 +44,7 @@ clean:
        $(DELETE) $(OBJDIR)$(PATHSEP)*.s19\r
        $(DELETE) $(OBJDIR)$(PATHSEP)*.map\r
        $(DELETE) $(OBJDIR)$(PATHSEP)*.d\r
+       $(DELETE) version.c\r
 \r
 .PHONY: all clean help\r
 help:\r
index 551ee694e493a0742b4e3878595c7454caf9ceb5..9696b008bf3a3103e0fcc8bd835e8e1c97750fb2 100644 (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);
 }
index 7605baa3c51f4a205329352fbb349440d72c4374..6f146f786a80aed72513da7445d4e73db9f116d6 100644 (file)
@@ -112,5 +112,6 @@ void LED(int led, int ms);
 void LEDsoff();\r
 int BUTTON_CLICKED(int ms);\r
 int BUTTON_HELD(int ms);\r
+void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information);\r
 \r
 #endif\r
index 3219a041de6fecf656fb27cc6ff8cc8183bd7eaf..b99cea2f2116479b3cf78e9afb9b069c6e2a5a6d 100644 (file)
@@ -12,6 +12,7 @@ SECTIONS
                *(.text.*)\r
                *(.glue_7)\r
                *(.glue_7t)\r
+               *(.version_information)\r
        } >osimage\r
        .rodata : { \r
                *(.rodata) \r
index a102bbb5a461e52ba1cc870c777077e6fe5b1f02..650ba22bacb31914c142ffeee9a0a882c940fb3b 100644 (file)
@@ -235,3 +235,37 @@ void SpinDelay(int ms)
   // convert to uS and call microsecond delay function\r
        SpinDelayUs(ms*1000);\r
 }\r
+\r
+/* Similar to FpgaGatherVersion this formats stored version information\r
+ * into a string representation. It takes a pointer to the struct version_information,\r
+ * verifies the magic properties, then stores a formatted string, prefixed by\r
+ * prefix in dst.
+ */\r
+void FormatVersionInformation(char *dst, int len, const char *prefix, void *version_information)\r
+{\r
+       struct version_information *v = (struct version_information*)version_information;\r
+       dst[0] = 0;\r
+       strncat(dst, prefix, len);\r
+       if(v->magic != VERSION_INFORMATION_MAGIC) {\r
+               strncat(dst, "Missing/Invalid version information", len);\r
+               return;\r
+       }\r
+       if(v->versionversion != 1) {\r
+               strncat(dst, "Version information not understood", len);\r
+               return;\r
+       }\r
+       if(!v->present) {\r
+               strncat(dst, "Version information not available", len);\r
+               return;\r
+       }\r
+       \r
+       strncat(dst, v->svnversion, len);\r
+       if(v->clean == 0) {\r
+               strncat(dst, "-unclean", len);\r
+       } else if(v->clean == 2) {\r
+               strncat(dst, "-suspect", len);\r
+       }\r
+       \r
+       strncat(dst, " ", len);\r
+       strncat(dst, v->buildtime, len);\r
+}\r
index 2b7671c7fc12762a8dd17c6e58c08a54e50f960b..30b55466b8f7b17404d2b48265ca268df6108e06 100644 (file)
@@ -2,7 +2,7 @@
 \r
 # DO NOT use thumb mode in the phase 1 bootloader since that generates a section with glue code\r
 ARMSRC = fromflash.c \r
-THUMBSRC = usb.c bootrom.c\r
+THUMBSRC = usb.c version.c bootrom.c\r
 ASMSRC = ram-reset.s flash-reset.s\r
 \r
 # Do not move this inclusion before the definition of {THUMB,ASM,ARM}SRC\r
@@ -19,8 +19,9 @@ clean:
        $(DELETE) $(OBJDIR)$(PATHSEP)*.s19\r
        $(DELETE) $(OBJDIR)$(PATHSEP)*.map\r
        $(DELETE) $(OBJDIR)$(PATHSEP)*.d\r
+       $(DELETE) version.c\r
 \r
-.PHONY: all clean help\r
+.PHONY: all clean help \r
 help:\r
        @echo Multi-OS Makefile, you are running on $(DETECTED_OS)\r
        @echo Possible targets:\r
index f6d5237cb7002843b4f69d5e4907e8ebfcfab8f0..0065e19e81cfb52101ac0ed05a87057bbf823b7d 100644 (file)
@@ -1,6 +1,6 @@
 #include <proxmark3.h>\r
 \r
-void __attribute__((section("bootphase1"))) CopyBootToRAM(void)\r
+void __attribute__((section(".bootphase1"))) CopyBootToRAM(void)\r
 {\r
        int i;\r
 \r
index 50218d684e5cefe5e12130cecd0863032e50bb69..d2e6648b8c8210528a7f5d1ff8c592f97dc06f25 100644 (file)
@@ -8,6 +8,18 @@ SECTIONS
     bootphase1 : {\r
        *(.startup) \r
        *(.bootphase1)\r
+       \r
+       /* It seems to be impossible to flush align a section at the\r
+          end of a memory segment. Instead, we'll put the version_information\r
+          wherever the linker wants it, and then put a pointer to the start\r
+          of the version information at the end of the section.\r
+          -- Henryk Plötz <henryk@ploetzli.ch> 2009-08-28 */\r
+          \r
+       _version_information_start = .;\r
+       *(.version_information);\r
+       \r
+       . = LENGTH(bootphase1) - 0x4; /* Skip ahead to the end */\r
+       LONG(_version_information_start)\r
     } >bootphase1\r
     \r
     bootphase2 : {\r
index a17b8a1bb2bd650be3b30937addb4adee345212e..04b0b330cf58742ae4c2893fbe62ad987443093b 100644 (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))) \
diff --git a/common/default_version.c b/common/default_version.c
new file mode 100644 (file)
index 0000000..b2d19b2
--- /dev/null
@@ -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 */
+}; 
diff --git a/common/version.c b/common/version.c
deleted file mode 100644 (file)
index cd78272..0000000
+++ /dev/null
@@ -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,
-};
index 2f3b483818830942b513854a8e7e89b730580948..7095fc853a22410400f2522e5297a6325f01c2f7 100644 (file)
@@ -60,4 +60,14 @@ void UsbStart(void);
 // if data are available.\r
 void UsbPacketReceived(BYTE *packet, int len);\r
 \r
+#define VERSION_INFORMATION_MAGIC 0x56334d50\r
+struct version_information {\r
+       int magic; /* Magic sequence to identify this as a correct version information structure. Must be VERSION_INFORMATION_MAGIC */ \r
+       char versionversion; /* Must be 1 */\r
+       char present; /* 1 if the version information could be created at compile time, otherwise 0 and the remaining fields (except for magic) are empty */\r
+       char clean; /* 1: Tree was clean, no local changes. 0: Tree was unclean. 2: Couldn't be determined */\r
+       char svnversion[9]; /* String with the SVN revision */\r
+       char buildtime[30]; /* string with the build time */\r
+} __attribute__((packed));\r
+\r
 #endif\r
diff --git a/tools/mkversion.pl b/tools/mkversion.pl
new file mode 100644 (file)
index 0000000..1c4dfcd
--- /dev/null
@@ -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
Impressum, Datenschutz