filename | src/bootstrap.c |
changeset | 1099:566cdeb157ec |
prev | 1095:a8b798030464 |
author | nkeynes |
date | Fri Dec 02 18:18:04 2011 +1000 (12 years ago) |
permissions | -rw-r--r-- |
last change | SH4 shadow-mode tweaks - Fix exceptions generated by the translator to account for the excepting instruction(s) in the cycle counts. - Compare floating point regs bitwise rather than with FP comparisons (otherwise can fail due to nan != nan) - Dump the translated block when we abort with an inconsistency |
file | annotate | diff | log | raw |
nkeynes@26 | 1 | /** |
nkeynes@561 | 2 | * $Id$ |
nkeynes@26 | 3 | * |
nkeynes@26 | 4 | * CD Bootstrap header parsing. Mostly for informational purposes. |
nkeynes@26 | 5 | * |
nkeynes@26 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@26 | 7 | * |
nkeynes@26 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@26 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@26 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@26 | 11 | * (at your option) any later version. |
nkeynes@26 | 12 | * |
nkeynes@26 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@26 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@26 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@26 | 16 | * GNU General Public License for more details. |
nkeynes@26 | 17 | */ |
nkeynes@1 | 18 | |
nkeynes@26 | 19 | #include "dream.h" |
nkeynes@26 | 20 | #include "bootstrap.h" |
nkeynes@26 | 21 | |
nkeynes@1 | 22 | static uint32_t compute_crc16( dc_bootstrap_head_t h ) |
nkeynes@1 | 23 | { |
nkeynes@1 | 24 | /* Note: Algorithm taken from http://mc.pp.se/dc/ip0000.bin.html */ |
nkeynes@1 | 25 | uint32_t i, c, n = 0xffff; |
nkeynes@1 | 26 | char *data = h->product_id; |
nkeynes@1 | 27 | for (i = 0; i < 16; i++) |
nkeynes@1 | 28 | { |
nkeynes@1 | 29 | n ^= (data[i]<<8); |
nkeynes@1 | 30 | for (c = 0; c < 8; c++) |
nkeynes@1 | 31 | if (n & 0x8000) |
nkeynes@1 | 32 | n = (n << 1) ^ 4129; |
nkeynes@1 | 33 | else |
nkeynes@1 | 34 | n = (n << 1); |
nkeynes@1 | 35 | } |
nkeynes@1 | 36 | return n & 0xffff; |
nkeynes@1 | 37 | } |
nkeynes@1 | 38 | |
nkeynes@26 | 39 | |
nkeynes@26 | 40 | static char *dc_peripherals[] = { "Uses WinCE", "Unknown (0x0000002)", |
nkeynes@736 | 41 | "Unknown (0x0000004)", "Unknown (0x0000008)", |
nkeynes@736 | 42 | "VGA Box", "Unknown (0x0000020)", |
nkeynes@736 | 43 | "Unknown (0x0000040)", "Unknown (0x0000080)", |
nkeynes@736 | 44 | "Other Expansions", "Puru Puru pack", |
nkeynes@736 | 45 | "Mike", "Memory card", |
nkeynes@736 | 46 | "Basic controller", "C button", |
nkeynes@736 | 47 | "D button", "X button", |
nkeynes@736 | 48 | "Y button", "Z button", |
nkeynes@736 | 49 | "Expanded direction buttons", |
nkeynes@736 | 50 | "Analog R trigger", "Analog L trigger", |
nkeynes@736 | 51 | "Analog horizontal", "Analog vertical", |
nkeynes@736 | 52 | "Expanded analog horizontal", |
nkeynes@736 | 53 | "Expanded analog vertical", |
nkeynes@736 | 54 | "Gun", "Keyboard", "Mouse" }; |
nkeynes@26 | 55 | |
nkeynes@26 | 56 | |
nkeynes@26 | 57 | /* Expansion units */ |
nkeynes@26 | 58 | #define DC_PERIPH_WINCE 0x0000001 |
nkeynes@26 | 59 | #define DC_PERIPH_VGABOX 0x0000010 |
nkeynes@26 | 60 | #define DC_PERIPH_OTHER 0x0000100 |
nkeynes@26 | 61 | #define DC_PERIPH_PURUPURU 0x0000200 |
nkeynes@26 | 62 | #define DC_PERIPH_MIKE 0x0000400 |
nkeynes@26 | 63 | #define DC_PERIPH_MEMCARD 0x0000800 |
nkeynes@26 | 64 | /* Basic requirements */ |
nkeynes@26 | 65 | #define DC_PERIPH_BASIC 0x0001000 /* Basic controls - start, a, b, arrows */ |
nkeynes@26 | 66 | #define DC_PERIPH_C_BUTTON 0x0002000 |
nkeynes@26 | 67 | #define DC_PERIPH_D_BUTTON 0x0004000 |
nkeynes@26 | 68 | #define DC_PERIPH_X_BUTTON 0x0008000 |
nkeynes@26 | 69 | #define DC_PERIPH_Y_BUTTON 0x0010000 |
nkeynes@26 | 70 | #define DC_PERIPH_Z_BUTTON 0x0020000 |
nkeynes@26 | 71 | #define DC_PERIPH_EXP_DIR 0x0040000 /* Expanded direction buttons */ |
nkeynes@26 | 72 | #define DC_PERIPH_ANALOG_R 0x0080000 /* Analog R trigger */ |
nkeynes@26 | 73 | #define DC_PERIPH_ANALOG_L 0x0100000 /* Analog L trigger */ |
nkeynes@26 | 74 | #define DC_PERIPH_ANALOG_H 0x0200000 /* Analog horizontal controller */ |
nkeynes@26 | 75 | #define DC_PERIPH_ANALOG_V 0x0400000 /* Analog vertical controller */ |
nkeynes@26 | 76 | #define DC_PERIPH_EXP_AH 0x0800000 /* Expanded analog horizontal (?) */ |
nkeynes@26 | 77 | #define DC_PERIPH_EXP_AV 0x1000000 /* Expanded analog vertical (?) */ |
nkeynes@26 | 78 | /* Optional peripherals */ |
nkeynes@26 | 79 | #define DC_PERIPH_GUN 0x2000000 |
nkeynes@26 | 80 | #define DC_PERIPH_KEYBOARD 0x4000000 |
nkeynes@26 | 81 | #define DC_PERIPH_MOUSE 0x8000000 |
nkeynes@26 | 82 | |
nkeynes@26 | 83 | /** |
nkeynes@26 | 84 | * Dump the bootstrap info to the output log for infomational/debugging |
nkeynes@26 | 85 | * purposes. |
nkeynes@167 | 86 | * @param detail true to include a ful information dump, false for just |
nkeynes@167 | 87 | * the facts, maam. |
nkeynes@26 | 88 | */ |
nkeynes@502 | 89 | void bootstrap_dump( void *data, gboolean detail ) |
nkeynes@1 | 90 | { |
nkeynes@1 | 91 | struct dc_bootstrap_head *head; |
nkeynes@1 | 92 | int i, got, periph, crc, hcrc; |
nkeynes@1 | 93 | char *prot_symbols; |
nkeynes@1 | 94 | char buf[512]; |
nkeynes@1 | 95 | |
nkeynes@1 | 96 | /* Dump out the bootstrap metadata table */ |
nkeynes@1 | 97 | head = (struct dc_bootstrap_head *)data; |
nkeynes@1 | 98 | prot_symbols = ((char *)data) + 0x3700; |
nkeynes@1 | 99 | memcpy( buf, head->product_name, 128 ); |
nkeynes@1 | 100 | for( i=127; i>0 && buf[i] == ' '; i-- ); |
nkeynes@1 | 101 | buf[i] = '\0'; |
nkeynes@1 | 102 | periph = strtol( head->peripherals, NULL, 16 ); |
nkeynes@167 | 103 | INFO( "Name: %s Author: %-16.16s", |
nkeynes@1 | 104 | buf, head->vendor_id ); |
nkeynes@1 | 105 | sprintf( buf, "%4.4s", head->crc ); |
nkeynes@1 | 106 | crc = compute_crc16(head); |
nkeynes@1 | 107 | hcrc = strtol( buf, NULL, 16 ); |
nkeynes@1 | 108 | INFO( " Product ID: %-10.10s Product Ver: %-6.6s Date: %-8.8s", |
nkeynes@1 | 109 | head->product_id, head->product_ver, head->product_date ); |
nkeynes@167 | 110 | if( detail ) { |
nkeynes@736 | 111 | INFO( " Header CRC: %04X (Computed %04X)", hcrc, crc ); |
nkeynes@736 | 112 | INFO( " Boot File: %-16.16s", head->boot_file ); |
nkeynes@736 | 113 | INFO( " Disc ID: %-11.11s Regions: %-8.8s Peripherals: %07X", |
nkeynes@736 | 114 | head->gdrom_id, head->regions, periph ); |
nkeynes@736 | 115 | strcpy( buf, " Supports: " ); |
nkeynes@736 | 116 | got = 0; |
nkeynes@736 | 117 | for( i=0; i<28; i++ ) { |
nkeynes@736 | 118 | if( periph & (1<<i) ){ |
nkeynes@736 | 119 | if( got ) strcat( buf, ", " ); |
nkeynes@736 | 120 | strcat( buf, dc_peripherals[i] ); |
nkeynes@736 | 121 | got = 1; |
nkeynes@736 | 122 | } |
nkeynes@736 | 123 | if( i == 11 ) i = 23; /* Skip 8-23 */ |
nkeynes@736 | 124 | } |
nkeynes@736 | 125 | INFO( buf, NULL ); |
nkeynes@736 | 126 | strcpy( buf, " Requires: " ); |
nkeynes@736 | 127 | got = 0; |
nkeynes@736 | 128 | for( i=12; i<24; i++ ) { |
nkeynes@736 | 129 | if( periph & (1<<i) ) { |
nkeynes@736 | 130 | if( got ) strcat( buf, ", " ); |
nkeynes@736 | 131 | strcat( buf, dc_peripherals[i] ); |
nkeynes@736 | 132 | got = 1; |
nkeynes@736 | 133 | } |
nkeynes@736 | 134 | } |
nkeynes@736 | 135 | INFO( buf, NULL ); |
nkeynes@1 | 136 | } |
nkeynes@1 | 137 | } |
nkeynes@1099 | 138 | |
nkeynes@1099 | 139 | /* Scramble/unscramble, based on Marcus Comstedt's algorithm. */ |
nkeynes@1099 | 140 | |
nkeynes@1099 | 141 | typedef uint16_t randseed; |
nkeynes@1099 | 142 | |
nkeynes@1099 | 143 | #define MAXBLOCK (2048*1024) |
nkeynes@1099 | 144 | #define CHUNKSIZE 32 |
nkeynes@1099 | 145 | #define NEXT(seed) (((seed = (seed*2109+9273)&0x7fff) + 0xC000) & 0xFFFF) |
nkeynes@1099 | 146 | |
nkeynes@1099 | 147 | void bootprogram_scramble( unsigned char *dest, unsigned char *src, size_t length ) |
nkeynes@1099 | 148 | { |
nkeynes@1099 | 149 | randseed seed = length & 0xFFFF; |
nkeynes@1099 | 150 | unsigned table[MAXBLOCK/32]; |
nkeynes@1099 | 151 | unsigned char *s = src; |
nkeynes@1099 | 152 | unsigned char *d = dest; |
nkeynes@1099 | 153 | |
nkeynes@1099 | 154 | for( unsigned blocksize = MAXBLOCK; blocksize >= CHUNKSIZE; blocksize >>= 1 ) { |
nkeynes@1099 | 155 | while( length >= blocksize ) { |
nkeynes@1099 | 156 | unsigned nchunks = blocksize/CHUNKSIZE; |
nkeynes@1099 | 157 | for( unsigned i=0; i<nchunks; i++ ) { |
nkeynes@1099 | 158 | table[i] = i; // Identity |
nkeynes@1099 | 159 | } |
nkeynes@1099 | 160 | for( unsigned i = nchunks-1; i != (unsigned)-1; --i ) { |
nkeynes@1099 | 161 | unsigned j = (NEXT(seed) * i)>>16; |
nkeynes@1099 | 162 | unsigned tmp = table[i]; |
nkeynes@1099 | 163 | table[i] = table[j]; |
nkeynes@1099 | 164 | table[j] = tmp; |
nkeynes@1099 | 165 | memcpy( d, s + CHUNKSIZE*table[i], CHUNKSIZE ); |
nkeynes@1099 | 166 | d+= CHUNKSIZE; |
nkeynes@1099 | 167 | } |
nkeynes@1099 | 168 | length -= blocksize; |
nkeynes@1099 | 169 | s += blocksize; |
nkeynes@1099 | 170 | } |
nkeynes@1099 | 171 | } |
nkeynes@1099 | 172 | if( length ) { |
nkeynes@1099 | 173 | memcpy( d, s, length ); |
nkeynes@1099 | 174 | } |
nkeynes@1099 | 175 | } |
nkeynes@1099 | 176 | |
nkeynes@1099 | 177 | void bootprogram_unscramble( unsigned char *dest, unsigned char *src, size_t length ) |
nkeynes@1099 | 178 | { |
nkeynes@1099 | 179 | randseed seed = length & 0xFFFF; |
nkeynes@1099 | 180 | unsigned table[MAXBLOCK/32]; |
nkeynes@1099 | 181 | unsigned char *s = src; |
nkeynes@1099 | 182 | unsigned char *d = dest; |
nkeynes@1099 | 183 | |
nkeynes@1099 | 184 | for( unsigned blocksize = MAXBLOCK; blocksize >= CHUNKSIZE; blocksize >>= 1 ) { |
nkeynes@1099 | 185 | while( length >= blocksize ) { |
nkeynes@1099 | 186 | unsigned nchunks = blocksize/CHUNKSIZE; |
nkeynes@1099 | 187 | for( unsigned i=0; i<nchunks; i++ ) { |
nkeynes@1099 | 188 | table[i] = i; // Identity |
nkeynes@1099 | 189 | } |
nkeynes@1099 | 190 | for( unsigned i = nchunks-1; i != (unsigned)-1; --i ) { |
nkeynes@1099 | 191 | unsigned j = (NEXT(seed) * i)>>16; |
nkeynes@1099 | 192 | unsigned tmp = table[i]; |
nkeynes@1099 | 193 | table[i] = table[j]; |
nkeynes@1099 | 194 | table[j] = tmp; |
nkeynes@1099 | 195 | memcpy( d + CHUNKSIZE*table[i], s, CHUNKSIZE ); |
nkeynes@1099 | 196 | s+= CHUNKSIZE; |
nkeynes@1099 | 197 | } |
nkeynes@1099 | 198 | length -= blocksize; |
nkeynes@1099 | 199 | d += blocksize; |
nkeynes@1099 | 200 | } |
nkeynes@1099 | 201 | } |
nkeynes@1099 | 202 | if( length ) { |
nkeynes@1099 | 203 | memcpy( d, s, length ); |
nkeynes@1099 | 204 | } |
nkeynes@1099 | 205 | } |
.