A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 330 lines 10 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2005 by Linus Nielsen Feltzing 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21#include <stdio.h> 22#include <stdlib.h> 23#include <string.h> 24#include "mkboot.h" 25 26#define SECTOR_SIZE 0x200 27#define RAW_IMAGE_SIZE 0x400000 28#define TOTAL_IMAGE_SIZE (RAW_IMAGE_SIZE + HEADER2_SIZE) 29#define ALIGNED_IMAGE_SIZE (TOTAL_IMAGE_SIZE + SECTOR_SIZE - (TOTAL_IMAGE_SIZE % SECTOR_SIZE)) 30#define HEADER1_SIZE SECTOR_SIZE 31#define HEADER2_SIZE 0x20 32 33#ifndef RBUTIL 34static void usage(void) 35{ 36 printf("usage: mkboot <target> <firmware file> <boot file> <output file>\n"); 37 printf("available targets:\n" 38 "\t-h100 Iriver H1x0\n" 39 "\t-h300 Iriver H3x0\n" 40 "\t-iax5 iAudio X5\n" 41 "\t-iam5 iAudio M5\n"); 42 43 exit(1); 44} 45#endif 46 47#ifndef RBUTIL 48int main(int argc, char *argv[]) 49{ 50 if(argc != 5) 51 { 52 usage(); 53 return 1; 54 } 55 56 if ( ! strcmp(argv[1], "-h100")) 57 return mkboot_iriver(argv[2], argv[3], argv[4], 0x1f0000); 58 59 if ( ! strcmp(argv[1], "-h300")) 60 return mkboot_iriver(argv[2], argv[3], argv[4], 0x3f0000); 61 62 if ( ! strcmp(argv[1], "-iax5")) 63 return mkboot_iaudio(argv[2], argv[3], argv[4], 0); 64 65 if ( ! strcmp(argv[1], "-iam5")) 66 return mkboot_iaudio(argv[2], argv[3], argv[4], 1); 67 68 usage(); 69 return 1; 70} 71#endif 72 73/* 74 * initial header size plus 75 * the rounded up size (includes the raw data and its length header) plus 76 * the checksums for the raw data and its length header 77 */ 78static unsigned char image[ALIGNED_IMAGE_SIZE + HEADER1_SIZE + ALIGNED_IMAGE_SIZE / SECTOR_SIZE]; 79 80int mkboot_iriver(const char* infile, const char* bootfile, const char* outfile, int origin) 81{ 82 FILE *f; 83 int i; 84 int len; 85 int actual_length, total_length, binary_length, num_chksums; 86 87 memset(image, 0xff, sizeof(image)); 88 89 /* First, read the iriver original firmware into the image */ 90 f = fopen(infile, "rb"); 91 if(!f) { 92 perror(infile); 93 return -1; 94 } 95 96 i = fread(image, 1, 16, f); 97 if(i < 16) { 98 perror(infile); 99 fclose(f); 100 return -2; 101 } 102 103 /* This is the length of the binary image without the scrambling 104 overhead (but including the ESTFBINR header) */ 105 binary_length = image[4] + (image[5] << 8) + 106 (image[6] << 16) + (image[7] << 24); 107 108 /* Read the rest of the binary data, but not the checksum block */ 109 len = binary_length+0x200-16; 110 i = fread(image+16, 1, len, f); 111 if(i < len) { 112 perror(infile); 113 fclose(f); 114 return -3; 115 } 116 117 fclose(f); 118 119 /* Now, read the boot loader into the image */ 120 f = fopen(bootfile, "rb"); 121 if(!f) { 122 perror(bootfile); 123 return -4; 124 } 125 126 fseek(f, 0, SEEK_END); 127 len = ftell(f); 128 129 fseek(f, 0, SEEK_SET); 130 131 i = fread(image+0x220 + origin, 1, len, f); 132 if(i < len) { 133 perror(bootfile); 134 fclose(f); 135 return -5; 136 } 137 138 fclose(f); 139 140 f = fopen(outfile, "wb"); 141 if(!f) { 142 perror(outfile); 143 return -6; 144 } 145 146 /* Patch the reset vector to start the boot loader */ 147 image[0x220 + 4] = image[origin + 0x220 + 4]; 148 image[0x220 + 5] = image[origin + 0x220 + 5]; 149 image[0x220 + 6] = image[origin + 0x220 + 6]; 150 image[0x220 + 7] = image[origin + 0x220 + 7]; 151 152 /* This is the actual length of the binary, excluding all headers */ 153 actual_length = origin + len; 154 155 /* Patch the ESTFBINR header */ 156 image[0x20c] = (actual_length >> 24) & 0xff; 157 image[0x20d] = (actual_length >> 16) & 0xff; 158 image[0x20e] = (actual_length >> 8) & 0xff; 159 image[0x20f] = actual_length & 0xff; 160 161 image[0x21c] = (actual_length >> 24) & 0xff; 162 image[0x21d] = (actual_length >> 16) & 0xff; 163 image[0x21e] = (actual_length >> 8) & 0xff; 164 image[0x21f] = actual_length & 0xff; 165 166 /* This is the length of the binary, including the ESTFBINR header and 167 rounded up to the nearest 0x200 boundary */ 168 binary_length = (actual_length + 0x20 + 0x1ff) & 0xfffffe00; 169 170 /* The number of checksums, i.e number of 0x200 byte blocks */ 171 num_chksums = binary_length / 0x200; 172 173 /* The total file length, including all headers and checksums */ 174 total_length = binary_length + num_chksums + 0x200; 175 176 /* Patch the scrambler header with the new length info */ 177 image[0] = total_length & 0xff; 178 image[1] = (total_length >> 8) & 0xff; 179 image[2] = (total_length >> 16) & 0xff; 180 image[3] = (total_length >> 24) & 0xff; 181 182 image[4] = binary_length & 0xff; 183 image[5] = (binary_length >> 8) & 0xff; 184 image[6] = (binary_length >> 16) & 0xff; 185 image[7] = (binary_length >> 24) & 0xff; 186 187 image[8] = num_chksums & 0xff; 188 image[9] = (num_chksums >> 8) & 0xff; 189 image[10] = (num_chksums >> 16) & 0xff; 190 image[11] = (num_chksums >> 24) & 0xff; 191 192 i = fwrite(image, 1, total_length, f); 193 if(i < total_length) { 194 perror(outfile); 195 fclose(f); 196 return -7; 197 } 198 199 printf("Wrote 0x%x bytes in %s\n", total_length, outfile); 200 201 fclose(f); 202 203 return 0; 204} 205 206/* iAudio firmware update file header size */ 207#define HEADER_SIZE 0x1030 208/* Address of flash contents that get overwritten by a firmware update. 209 * Contents before this address contain the preloader and are not affected 210 * by a firmware update. 211 * -> Firmware update file contents starting at offset HEADER_SIZE end up 212 * in flash at address FLASH_START 213 */ 214#define FLASH_START 0x00010000 215/* Start of unused space in original firmware (flash address, not file 216 * offset!) where we patch in the Rockbox loader */ 217#define ROCKBOX_BOOTLOADER 0x00150000 218/* End of unused space in original firmware */ 219#define BOOTLOADER_LIMIT 0x00170000 220 221/* Patch the Rockbox bootloader into free space in the original firmware 222 * (starting at 0x150000). The preloader starts execution of the OF at 223 * 0x10000 which normally contains a jsr 0x10010. We also patch this to 224 * do a jsr 0x150000 to the Rockbox dual boot loader instead. If it then 225 * decides to start the OF instead of Rockbox, it simply does a jmp 226 * 0x10010 instead of loading Rockbox from disk. 227 */ 228int mkboot_iaudio(const char* infile, const char* bootfile, const char* outfile, int model_nr) 229{ 230 size_t flength, blength; 231 unsigned char *bbuf, *fbuf, *p; 232 const unsigned char fsig[] = { 233 0x4e, 0xb9, 0x00, 0x01, 0x00, 0x10 }; /* jsr 0x10010 */ 234 unsigned char bsig[2][8] = { 235 /* dualboot signatures */ 236 { 0x60, 0x06, 0x44, 0x42, 0x69, 0x61, 0x78, 0x35 }, /* X5 */ 237 { 0x60, 0x06, 0x44, 0x42, 0x69, 0x61, 0x6d, 0x35 }, /* M5 */ }; 238 FILE *ffile, *bfile, *ofile; 239 unsigned char sum = 0; 240 int i; 241 242 /* read input files */ 243 if ((bfile = fopen(bootfile, "rb")) == NULL) { 244 perror("Cannot open Rockbox bootloader file.\n"); 245 return 1; 246 } 247 248 fseek(bfile, 0, SEEK_END); 249 blength = ftell(bfile); 250 fseek(bfile, 0, SEEK_SET); 251 252 if (blength + ROCKBOX_BOOTLOADER >= BOOTLOADER_LIMIT) { 253 fprintf(stderr, "Rockbox bootloader is too big.\n"); 254 return 1; 255 } 256 257 if ((ffile = fopen(infile, "rb")) == NULL) { 258 perror("Cannot open original firmware file."); 259 return 1; 260 } 261 262 fseek(ffile, 0, SEEK_END); 263 flength = ftell(ffile); 264 fseek(ffile, 0, SEEK_SET); 265 266 bbuf = malloc(blength); 267 fbuf = malloc(flength); 268 269 if (!bbuf || !fbuf) { 270 fprintf(stderr, "Out of memory.\n"); 271 return 1; 272 } 273 274 if ( fread(bbuf, 1, blength, bfile) < blength 275 || fread(fbuf, 1, flength, ffile) < flength) { 276 fprintf(stderr, "Read error.\n"); 277 return 1; 278 } 279 fclose(bfile); 280 fclose(ffile); 281 282 /* verify format of input files */ 283 if (blength < 0x10 || memcmp(bbuf, bsig[model_nr], sizeof(bsig[0]))) { 284 fprintf(stderr, "Rockbox bootloader format error (is it bootloader.bin?).\n"); 285 return 1; 286 } 287 if (flength < HEADER_SIZE-FLASH_START+BOOTLOADER_LIMIT 288 || memcmp(fbuf+HEADER_SIZE, fsig, sizeof(fsig))) { 289 fprintf(stderr, "Original firmware format error.\n"); 290 return 1; 291 } 292 293 /* verify firmware is not overrun */ 294 for (i = ROCKBOX_BOOTLOADER; i < BOOTLOADER_LIMIT; i++) { 295 if (fbuf[HEADER_SIZE-FLASH_START+i] != 0xff) { 296 fprintf(stderr, "Original firmware has grown too much.\n"); 297 return 1; 298 } 299 } 300 301 /* change jsr 0x10010 to jsr DUAL_BOOTLOADER */ 302 p = fbuf + HEADER_SIZE + 2; 303 *p++ = (ROCKBOX_BOOTLOADER >> 24) & 0xff; 304 *p++ = (ROCKBOX_BOOTLOADER >> 16) & 0xff; 305 *p++ = (ROCKBOX_BOOTLOADER >> 8) & 0xff; 306 *p++ = (ROCKBOX_BOOTLOADER ) & 0xff; 307 308 p = fbuf + HEADER_SIZE + ROCKBOX_BOOTLOADER - FLASH_START; 309 memcpy(p, bbuf, blength); 310 311 /* recalc checksum */ 312 for (i = HEADER_SIZE; (size_t)i < flength; i++) 313 sum += fbuf[i]; 314 fbuf[0x102b] = sum; 315 316 /* write output */ 317 if ((ofile = fopen(outfile, "wb")) == NULL) { 318 perror("Cannot open output file"); 319 return 1; 320 } 321 if (fwrite(fbuf, 1, flength, ofile) < flength) { 322 fprintf(stderr, "Write error.\n"); 323 return 1; 324 } 325 fclose(ofile); 326 free(bbuf); 327 free(fbuf); 328 329 return 0; 330}