]> git.zerfleddert.de Git - rsbs2/blobdiff - firmware.c
fileaccess cleanups
[rsbs2] / firmware.c
index a5bdfdb16eb6c795ec27ed8a1d1cd830ab3831fb..b57501277aa90b091d189e7fec940696c8d19458 100644 (file)
@@ -8,6 +8,7 @@
 #include <string.h>
 #include <strings.h>
 #include "rsb-crc.h"
+#include "filesystem.h"
 
 #define FINDSTR(addr, str) (!strncmp((char*)addr, str, strlen(str)))
 
@@ -25,20 +26,37 @@ struct properties {
        unsigned char val[];
 };
 
+#define PROP_ACTION_TRUE       (1<<0)
+#define PROP_ACTION_FALSE      (1<<1)
+#define PROP_ACTION_RO         (1<<2)
+#define PROP_ACTION_RW         (1<<3)
+
+#define PROP_STATUS_NOTFOUND   (0)
+#define PROP_STATUS_WRONGTYPE  (1<<0)
+#define PROP_STATUS_WRONGRIGHTS        (1<<1)
+#define PROP_STATUS_SAMEVAL    (1<<2)
+#define PROP_STATUS_SUCCESS    (1<<3)
+
+struct propaction {
+       char *property;
+       unsigned int action;
+       unsigned int status;
+       struct propaction *next;
+};
+
 void show_properties(unsigned char *fw, int len)
 {
-       int i;
+       struct file_entry *fent;
 
-       for (i = 0; i < (len-100 /* XXX */); i++) {
-               if (FINDSTR(fw+i, "/default/fw_prop/") ||
-                   FINDSTR(fw+i, "/default/fw_setup/") ||
-                   FINDSTR(fw+i, "/default/oem_prop/")) {
+       for (fent = get_next_file(fw, len); fent != NULL; fent = get_next_file(NULL, 0)) {
+               if (FINDSTR(fent->name, "/default/fw_prop/") ||
+                   FINDSTR(fent->name, "/default/fw_setup/") ||
+                   FINDSTR(fent->name, "/default/oem_prop/")) {
                        struct properties *prop;
-                       unsigned char *pos = fw + i;
 
-                       printf("0x%08x: found setting: %s: ", i, pos);
+                       printf("0x%08x: found setting: %s ", fent->start - fw, fent->name);
 
-                       prop = (struct properties*)(pos + strlen((char*)pos) + 1);
+                       prop = (struct properties*)fent->start;
                        
                        if (prop->magic != 0x83011111) {
                                printf("ignoring...\n");
@@ -46,7 +64,7 @@ void show_properties(unsigned char *fw, int len)
                        }
 
                        if (prop->type1 == 0x00 && prop->type2 == 0x04) {
-                               printf("STRING: %s ", prop->val);
+                               printf("STRING: '%s' ", prop->val);
                        } else if (prop->type1 == 0x01 && prop->type2 == 0x01) {
                                printf("BOOL: %s ",(*prop->val ? "TRUE" : "FALSE"));
                        } else if (prop->type1 == 0x04 && prop->type2 == 0x02) {
@@ -57,42 +75,358 @@ void show_properties(unsigned char *fw, int len)
                        }
 
                        if (prop->right_rw == 0x00 && prop->rw_mask == 0x00) {
-                               printf("(R-) ");
+                               printf("(R-)");
                        } else if (prop->right_rw == 0x01) {
-                               printf("(RW mask: 0x%02x) ", prop->rw_mask);
+                               printf("(RW mask: 0x%02x)", prop->rw_mask);
                        } else {
-                               printf("(UNK 0x%02x 0x%02x) ", prop->right_rw, prop->rw_mask);
+                               printf("(UNK 0x%02x 0x%02x)", prop->right_rw, prop->rw_mask);
                        }
-                       printf("\n");
+                       printf(", length: %d\n", fent->length);
+               }
+       }
+}
+
+void change_properties(unsigned char *fw, int len, struct propaction *paction)
+{
+       struct file_entry *fent;
+       struct propaction *cpaction;
+
+       for (fent = get_next_file(fw, len); fent != NULL; fent = get_next_file(NULL, 0)) {
+               cpaction = paction;
+               while (cpaction != NULL) {
+                       if (FINDSTR(fent->name, cpaction->property)) {
+                               break;
+                       }
+                       cpaction = cpaction->next;
                }
+               if (cpaction != NULL) {
+                       struct properties *prop;
+
+                       prop = (struct properties*)fent->start;
+
+                       if (prop->magic != 0x83011111) {
+                               continue;
+                       }
+
+                       if (cpaction->action & (PROP_ACTION_TRUE|PROP_ACTION_FALSE)) {
+                               if (prop->type1 == 0x01 && prop->type2 == 0x01) {
+                                       if (cpaction->action & PROP_ACTION_TRUE) {
+                                               if (*prop->val == 0x00) {
+                                                       *prop->val = 0x01;
+                                                       cpaction->status |= PROP_STATUS_SUCCESS;
+                                               } else {
+                                                       cpaction->status |= PROP_STATUS_SAMEVAL;
+                                               }
+                                       } else {
+                                               if (*prop->val == 0x01) {
+                                                       *prop->val = 0x00;
+                                                       cpaction->status |= PROP_STATUS_SUCCESS;
+                                               } else {
+                                                       cpaction->status |= PROP_STATUS_SAMEVAL;
+                                               }
+                                       }
+                               } else {
+                                       cpaction->status = PROP_STATUS_WRONGTYPE;
+                               }
+                       }
+                       if (cpaction->action & PROP_ACTION_RW) {
+                               if (prop->right_rw == 0x00 && prop->rw_mask == 0x00) {
+                                       prop->right_rw = 0x01;
+                                       prop->rw_mask = 0x02;
+                                       cpaction->status |= PROP_STATUS_SUCCESS;
+                               } else {
+                                       cpaction->status |= PROP_STATUS_WRONGRIGHTS;
+                               }
+                       }
+                       if (cpaction->action & PROP_ACTION_RO) {
+                               if (prop->right_rw == 0x01 && prop->rw_mask == 0x02) {
+                                       prop->right_rw = 0x00;
+                                       prop->rw_mask = 0x00;
+                                       cpaction->status |= PROP_STATUS_SUCCESS;
+                               } else {
+                                       cpaction->status |= PROP_STATUS_WRONGRIGHTS;
+                               }
+                       }
+               }
+       }
+}
+
+#define BD_SERIAL1     0x14,0x02
+#define BD_ICMB                0x14,0x04
+#define BD_LAN         0x14,0x08
+#define BD_SERIAL2     0x14,0x10
+#define BD_SERIAL3     0x14,0x20
+#define BD_USB         0x14,0x40
+#define BD_PCI         0x15,0x03
+#define BD_LPC         0x15,0x04
+#define BD_VGA         0x15,0x08
+#define BD_BATTERY     0x15,0x10
+#define BD_ACDC                0x15,0x20
+#define BD_STANDBY     0x15,0x40
+#define BD_POWERCONN   0x15,0x70
+#define BD_DVI         0x15,0x80
+#define BD_PWRATX      0x16,0x01
+#define BD_PWRRELAY    0x16,0x02
+#define BD_PS2A                0x19,0xff
+
+#define MAGIC(fn, args...) fn(args)
+
+#define _BD_IS_SET(bd, byte, bits) (bd[byte] & bits)
+#define BD_IS_SET(bd, ident) MAGIC(_BD_IS_SET, bd, BD_##ident)
+#define BD_TEXT(bd, ident) (BD_IS_SET(bd, ident) ? "TRUE" : "FALSE")
+
+#define _BD_SET(bd, byte, bits) (bd[byte] |= bits)
+#define BD_SET(bd, ident) MAGIC(_BD_SET, bd, BD_##ident)
+
+void print_boarddescription(unsigned char *bd)
+{
+       int j;
+
+       for (j = 0; j < 32; j++) {
+               printf("%02x ", *(bd+j));
        }
+       printf("\n");
+
+       /* com/agilent/rmc/amr/AmrMaster.class
+        * com/agilent/rmc/mgui/RmcPanel.class
+        * com/agilent/rmc/mgui/panels/AvrManualConfig.class
+        * com/agilent/rmc/mgui/panels/CardConf.jad
+        * com/agilent/rmc/mgui/panels/PowerMgmtConf.jad
+        * com/agilent/rmc/mgui/panels/RemoteDiskConf.jad
+        */
+       printf("\tserial1Present\t\t: %s\n", BD_TEXT(bd, SERIAL1));
+       printf("\ticmbPresent\t\t: %s\n", BD_TEXT(bd, ICMB));
+       printf("\tlanPresent\t\t: %s\n", BD_TEXT(bd, LAN));
+       printf("\tserial2Present\t\t: %s\n", BD_TEXT(bd, SERIAL2));
+       printf("\tserial3Present\t\t: %s\n", BD_TEXT(bd, SERIAL3));
+       printf("\tusbPresent\t\t: %s\n", BD_TEXT(bd, USB));
+       printf("\tpciPresent\t\t: %s\n", BD_TEXT(bd, PCI));
+       printf("\tlpcPresent\t\t: %s\n", BD_TEXT(bd, LPC));
+       printf("\tvgaPresent\t\t: %s\n", BD_TEXT(bd, VGA));
+       printf("\tbatteryPresent\t\t: %s\n", BD_TEXT(bd, BATTERY));
+       printf("\tacdcPresent\t\t: %s\n", BD_TEXT(bd, ACDC));
+       printf("\tstandbyPresent\t\t: %s\n", BD_TEXT(bd, STANDBY));
+       printf("\thasPowerConnectors\t: %s\n", BD_TEXT(bd, POWERCONN));
+       printf("\tdviPresent\t\t: %s\n", BD_TEXT(bd, DVI));
+       printf("\tpowerSwitchATX\t\t: %s\n", BD_TEXT(bd, PWRATX));
+       printf("\tpowerSwitchRelay\t: %s\n", BD_TEXT(bd, PWRRELAY));
+       /* 22 & 4 */
+       printf("\tps2aPresent\t\t: %s\n", BD_TEXT(bd, PS2A));
 }
 
 void handle_boarddescription(unsigned char *fw, int len, int patch)
 {
-       /* 0x01 0x01 0x50 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x88 0x02 0xac 0x01 0xd0 0x05 0x00 0x00 0x6a 0x3a 0x00 0x00 0x06 0x00 0x01 0x00 0x00 0x00 0x00 0x00 */
+       struct file_entry *fent;
+       unsigned char *pos;
+       
+       for (fent = get_next_file(fw, len); fent != NULL; fent = get_next_file(NULL, 0)) {
+               if (!strcmp(fent->name, "pdata"))
+                       break;
+       }
+
+       if (fent == NULL) {
+               fprintf(stderr, "pdata file not found, aborting!\n");
+               exit(1);
+       }
+
+
+       pos = fent->start;
+       /* MAGIC? */
+       if (*((unsigned int*)pos) != 0x00002802) {
+               fprintf(stderr, "pdata magic does not match, aborting!\n");
+               exit(1);
+       }
+
+       pos += 26;
+
+       /* MAGIC2? */
+       if (*((unsigned int*)pos) != 0x00500101) {
+               fprintf(stderr, "pdata magic2 does not match, aborting!\n");
+               exit(1);
+       }
+
+       if (patch) {
+               /* Enable ATX and relay power switching */
+               BD_SET(pos, PWRATX);
+               BD_SET(pos, PWRRELAY);
+       }
+
+       printf("0x%08x: BOARD_DESCRIPTION: ", fent->start - fw);
+       print_boarddescription(pos);
+}
+
+void syntax(char *name)
+{
+       fprintf(stderr,"Syntax: %s parameters firmware.bin\n", name);
+       fprintf(stderr,"parameters as follows:\n");
+       fprintf(stderr,"\t-d\t\t\tdisplay all properties of the image\n");
+       fprintf(stderr,"\t-u\t\t\tupdate checksum of the image\n");
+       fprintf(stderr,"\t-b\t\t\tmodify BOARD_DESCRIPTION for more power-switch options\n");
+       fprintf(stderr,"\t-e\t\t\textract files in firmware\n");
+       fprintf(stderr,"\t-l\t\t\tlist files in firmware\n");
+       fprintf(stderr,"\t-t property\t\tset 'property' to true\n");
+       fprintf(stderr,"\t-f property\t\tset 'property' to false\n");
+       fprintf(stderr,"\t-w property\t\tallow read-write access to 'property'\n");
+       fprintf(stderr,"\t-r property\t\tallow read-only access to 'property'\n");
+       fprintf(stderr,"\t-x fw_file=local_file\treplace or add fw_file with content of local_file\n");
+       exit(1);
+}
+
+void add_action(int opt, char *optarg, struct propaction **paction) {
+       struct propaction *pos = *paction;
+       struct propaction *prev = NULL;
+       
+       while (pos != NULL) {
+               if (!strcmp(pos->property, optarg))
+                       break;
+               prev = pos;
+               pos = pos->next;
+       }
+
+       if (pos == NULL) {
+               pos = malloc(sizeof(struct propaction));
+               if (pos == NULL) {
+                       perror("malloc");
+                       exit(1);
+               }
+               bzero(pos, sizeof(struct propaction));
+               pos->property = optarg;
+
+               if (prev == NULL) {
+                       *paction = pos;
+               } else {
+                       prev->next = pos;
+               }
+       }
+
+       switch(opt) {
+               case 't':
+                       if (pos->action & PROP_ACTION_FALSE) {
+                               fprintf(stderr,"inconsistent requests for %s\n",pos->property);
+                               exit(1);
+                       }
+                       pos->action |= PROP_ACTION_TRUE;
+                       break;
+               case 'f':
+                       if (pos->action & PROP_ACTION_TRUE) {
+                               fprintf(stderr,"inconsistent requests for %s\n",pos->property);
+                               exit(1);
+                       }
+                       pos->action |= PROP_ACTION_FALSE;
+                       break;
+               case 'w':
+                       if (pos->action & PROP_ACTION_RO) {
+                               fprintf(stderr,"inconsistent requests for %s\n",pos->property);
+                               exit(1);
+                       }
+                       pos->action |= PROP_ACTION_RW;
+                       break;
+               case 'r':
+                       if (pos->action & PROP_ACTION_RW) {
+                               fprintf(stderr,"inconsistent requests for %s\n",pos->property);
+                               exit(1);
+                       }
+                       pos->action |= PROP_ACTION_RO;
+                       break;
+       }
+}
+
+int check_crc(unsigned char *fw, int len)
+{
+       int ret;
+       unsigned int crc, oldcrc;
+
+       ret = rsb_crc2(fw, len, 0x55335053, &crc);
+       oldcrc = (unsigned int)*((unsigned int*)(fw + len - 4));
+
+       printf("Checksum: 0x%08x (%s), should be: 0x%08x\n",
+               crc,
+               (ret ? "NOT OK" : "OK"),
+               oldcrc);
+
+       return ret;
+}
+
+void check_image(unsigned char *fw, int len)
+{
+       struct file_entry *fent;
+       char *last_name = NULL;
+
+       /* get_next_file will abort on error */
+       fent = get_next_file(fw, len);
+       while (fent != NULL) {
+               last_name = fent->name;
+               fent = get_next_file(NULL, 0);
+       }
 }
 
 int main(int argc, char **argv)
 {
        struct stat statbuf;
+       char *file = NULL;
        unsigned char *fw;
        int fd;
        int remaining;
        int ret;
-       unsigned int crc, oldcrc;
+       int opt;
+       unsigned int crc;
+       struct propaction *paction = NULL;
+       int showall = 0;
+       int update_crc = 0;
+       int patch_bd = 0;
+       int patch_fw = 0;
+       int extract = 0;
+       int list = 0;
 
-       if (argc != 2) {
-               fprintf(stderr,"Syntax: %s firmware.bin\n", argv[0]);
-               exit(1);
+       if (argc < 2)
+               syntax(argv[0]);
+
+       while ((opt = getopt(argc, argv, "dubelt:f:w:r:x:")) != -1) {
+               switch(opt) {
+                       case 'd':
+                               showall = 1;
+                               break;
+                       case 'u':
+                               update_crc = 1;
+                               break;
+                       case 'b':
+                               patch_bd = 1;
+                               break;
+                       case 'e':
+                               extract = 1;
+                               break;
+                       case 'l':
+                               list = 1;
+                               break;
+                       case 't':
+                       case 'f':
+                       case 'w':
+                       case 'r':
+                               patch_fw = 1;
+                               add_action(opt, optarg, &paction);
+                               break;
+                       case 'x':
+                               replace_add_file(NULL, 0, NULL, NULL);
+                               break;
+                       default:
+                               syntax(argv[0]);
+               }
        }
 
-       if (stat(argv[1], &statbuf) == -1) {
+       if (argc > optind) {
+               file = argv[optind];
+       } else {
+               syntax(argv[0]);
+       }
+
+       if (stat(file, &statbuf) == -1) {
+               fprintf(stderr,"%s: ", file);
                perror("stat");
                exit(1);
        }
 
-       if ((fd = open(argv[1], O_RDONLY)) == -1) {
+       if ((fd = open(file, O_RDONLY)) == -1) {
+               fprintf(stderr,"%s: ", file);
                perror("open");
                exit(1);
        }
@@ -113,23 +447,84 @@ int main(int argc, char **argv)
                }
                remaining -= ret;
        }
+       close(fd);
 
-       ret = rsb_crc2(fw, statbuf.st_size, 0x55335053, &crc);
-       oldcrc = (unsigned int)*((unsigned int*)(fw + statbuf.st_size - 4));
+       ret = check_crc(fw, statbuf.st_size);
+       if ((ret != 0) && (!update_crc)) {
+               fprintf(stderr,"Checksum incorrect, aborting...\n");
+               exit(1);
+       }
 
-       printf("Checksum: 0x%08x (%s), should be: 0x%08x\n",
-               crc,
-               (ret ? "NOT OK" : "OK"),
-               oldcrc);
-       
-       if (1) {
+       check_image(fw, statbuf.st_size - 4);
+
+       if (patch_fw) {
+               struct propaction *cpaction = paction;
+
+               change_properties(fw, statbuf.st_size - 4, paction);
+
+               printf("\nProperty change results:\n");
+               while(cpaction != NULL) {
+                       printf("%s: ", cpaction->property);
+
+                       if (cpaction->status == PROP_STATUS_NOTFOUND)
+                               printf("NOTFOUND ");
+                       if (cpaction->status & PROP_STATUS_SUCCESS)
+                               printf("SUCCESS ");
+                       if (cpaction->status & PROP_STATUS_SAMEVAL)
+                               printf("SAMEVAL ");
+                       if (cpaction->status & PROP_STATUS_WRONGTYPE)
+                               printf("WRONGTYPE ");
+                       if (cpaction->status & PROP_STATUS_WRONGRIGHTS)
+                               printf("WRONGRIGHTS ");
+                       printf("\n");
+                       
+                       cpaction = cpaction->next;
+               }
+               printf("\n");
+       }
+
+       if (patch_bd) {
+               handle_boarddescription(fw, statbuf.st_size - 4, 1);
+       }
+
+       if (showall) {
                show_properties(fw, statbuf.st_size - 4);
                handle_boarddescription(fw, statbuf.st_size - 4, 0);
-               if (0) {
-                       ret = rsb_crc2(fw, statbuf.st_size, 0x55335053, &crc);
-                       printf("Checksum: 0x%08x\n", crc);
-               }
        }
 
+       if (list) {
+               list_files(fw, statbuf.st_size - 4);
+       }
+
+       if (extract) {
+               extract_files(fw, statbuf.st_size - 4);
+       }
+
+       if (update_crc || patch_fw || patch_bd) {
+               ret = rsb_crc2(fw, statbuf.st_size, 0x55335053, &crc);
+               if (ret == 4) {
+                       *((unsigned int*)(fw + statbuf.st_size - 4)) = crc;
+               }
+
+               check_image(fw, statbuf.st_size-4);
+
+               if (check_crc(fw, statbuf.st_size) == 0) {
+                       char *newfile;
+
+                       newfile = malloc(strlen(file) + strlen(".patched") + 1);
+                       if (newfile == NULL) {
+                               perror("malloc");
+                               exit(1);
+                       }
+                       strcpy(newfile, file);
+                       strcat(newfile, ".patched");
+
+                       printf("Firmware ");
+                       write_file(newfile, fw, statbuf.st_size);
+               } else {
+                       fprintf(stderr,"Can't set correct checksum, aborting...\n");
+               }
+       }
+       
        exit(0);
 }
Impressum, Datenschutz