├── .gitignore ├── DriveCom ├── DriveCom.sln ├── DriveCom.v11.suo └── DriveCom │ ├── App.config │ ├── DriveCom.csproj │ ├── DriveCom.csproj.user │ ├── PhisonDevice.cs │ ├── PhisonDo.csproj.user │ ├── Properties │ └── AssemblyInfo.cs │ └── Startup.cs ├── EmbedPayload ├── EmbedPayload.exe.config ├── EmbedPayload.sln ├── EmbedPayload.v11.suo ├── EmbedPayload.vshost.exe.config └── EmbedPayload │ ├── App.config │ ├── EmbedPayload.csproj │ ├── Properties │ └── AssemblyInfo.cs │ └── Startup.cs ├── Injector ├── Injector.sln ├── Injector.v11.suo └── Injector │ ├── App.config │ ├── DoPatch.csproj.user │ ├── FirmwareImage.cs │ ├── FirmwareSection.cs │ ├── Injector.csproj │ ├── Injector.csproj.user │ ├── Properties │ └── AssemblyInfo.cs │ └── Startup.cs ├── LICENSE ├── README.md ├── docs └── PinsToShortUponPlugInForBootMode.jpg ├── firmware ├── build.bat ├── control.c ├── defs.h ├── main.c ├── scsi.c ├── test.bat ├── timers.c ├── timers.h ├── usb.c └── usb.h ├── patch ├── base.c ├── build.bat └── defs.h ├── templates ├── BNdummy.bin └── FWdummy.bin └── tools ├── hex2bin.exe └── sfk.exe /.gitignore: -------------------------------------------------------------------------------- 1 | **/bin/Debug/* 2 | **/obj/Debug/* 3 | **/bin/Release/* 4 | **/obj/Release/* 5 | firmware/bin/* 6 | patch/bin/* 7 | patch/equates.h 8 | tools/* 9 | -------------------------------------------------------------------------------- /DriveCom/DriveCom.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriveCom", "DriveCom\DriveCom.csproj", "{25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /DriveCom/DriveCom.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/DriveCom/DriveCom.v11.suo -------------------------------------------------------------------------------- /DriveCom/DriveCom/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/DriveCom.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2} 8 | Exe 9 | Properties 10 | DriveCom 11 | DriveCom 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | ..\..\tools\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | true 26 | 27 | 28 | AnyCPU 29 | pdbonly 30 | true 31 | ..\..\tools\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/DriveCom.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | /drive=E /burner=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\BN03V104M.BIN /firmware=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\FW03FF01V10353M.BIN 5 | 6 | 7 | /drive=E 8 | 9 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/PhisonDevice.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.InteropServices; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace DriveCom 11 | { 12 | public class PhisonDevice 13 | { 14 | private char _driveLetter; 15 | private SafeFileHandle _handle; 16 | 17 | public enum RunMode 18 | { 19 | Unknown, 20 | BootMode, 21 | Burner, 22 | HardwareVerify, 23 | Firmware 24 | } 25 | 26 | [Flags] 27 | public enum EFileAttributes : uint 28 | { 29 | Readonly = 0x00000001, 30 | Hidden = 0x00000002, 31 | System = 0x00000004, 32 | Directory = 0x00000010, 33 | Archive = 0x00000020, 34 | Device = 0x00000040, 35 | Normal = 0x00000080, 36 | Temporary = 0x00000100, 37 | SparseFile = 0x00000200, 38 | ReparsePoint = 0x00000400, 39 | Compressed = 0x00000800, 40 | Offline = 0x00001000, 41 | NotContentIndexed = 0x00002000, 42 | Encrypted = 0x00004000, 43 | Write_Through = 0x80000000, 44 | Overlapped = 0x40000000, 45 | NoBuffering = 0x20000000, 46 | RandomAccess = 0x10000000, 47 | SequentialScan = 0x08000000, 48 | DeleteOnClose = 0x04000000, 49 | BackupSemantics = 0x02000000, 50 | PosixSemantics = 0x01000000, 51 | OpenReparsePoint = 0x00200000, 52 | OpenNoRecall = 0x00100000, 53 | FirstPipeInstance = 0x00080000 54 | } 55 | 56 | [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] 57 | public static extern SafeFileHandle CreateFile( 58 | string fileName, 59 | [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, 60 | [MarshalAs(UnmanagedType.U4)] FileShare fileShare, 61 | IntPtr securityAttributes, 62 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 63 | [MarshalAs(UnmanagedType.U4)] EFileAttributes flags, 64 | IntPtr template); 65 | 66 | [DllImport("kernel32.dll")] 67 | static public extern int CloseHandle(SafeFileHandle hObject); 68 | 69 | public const byte SCSI_IOCTL_DATA_OUT = 0; 70 | public const byte SCSI_IOCTL_DATA_IN = 1; 71 | 72 | [StructLayout(LayoutKind.Sequential)] 73 | class SCSI_PASS_THROUGH_DIRECT 74 | { 75 | private const int _CDB_LENGTH = 16; 76 | 77 | public short Length; 78 | public byte ScsiStatus; 79 | public byte PathId; 80 | public byte TargetId; 81 | public byte Lun; 82 | public byte CdbLength; 83 | public byte SenseInfoLength; 84 | public byte DataIn; 85 | public int DataTransferLength; 86 | public int TimeOutValue; 87 | public IntPtr DataBuffer; 88 | public uint SenseInfoOffset; 89 | 90 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = _CDB_LENGTH)] 91 | public byte[] Cdb; 92 | 93 | public SCSI_PASS_THROUGH_DIRECT() 94 | { 95 | Cdb = new byte[_CDB_LENGTH]; 96 | } 97 | }; 98 | 99 | [StructLayout(LayoutKind.Sequential)] 100 | class SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER 101 | { 102 | private const int _SENSE_LENGTH = 32; 103 | internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT(); 104 | 105 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = _SENSE_LENGTH)] 106 | internal byte[] sense; 107 | 108 | public SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER() 109 | { 110 | sense = new byte[_SENSE_LENGTH]; 111 | } 112 | }; 113 | 114 | [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] 115 | static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, 116 | IntPtr lpInBuffer, uint nInBufferSize, 117 | IntPtr lpOutBuffer, uint nOutBufferSize, 118 | out uint lpBytesReturned, IntPtr lpOverlapped); 119 | 120 | /// 121 | /// Creates a reference to a device with a Phison USB controller. 122 | /// 123 | /// The Windows drive letter representing the device. 124 | public PhisonDevice(char driveLetter) 125 | { 126 | _driveLetter = driveLetter; 127 | } 128 | 129 | /// 130 | /// Opens a connection to the device. 131 | /// 132 | public void Open() 133 | { 134 | _handle = CreateFile(string.Format("\\\\.\\{0}:", _driveLetter), FileAccess.ReadWrite, FileShare.ReadWrite, 135 | IntPtr.Zero, FileMode.Open, EFileAttributes.NoBuffering, IntPtr.Zero); 136 | } 137 | 138 | public byte[] RequestVendorInfo() 139 | { 140 | var data = SendCommand(new byte[] { 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, 141 | 512 + 16); 142 | byte[] ret = null; 143 | 144 | if (data != null) 145 | { 146 | ret = data.Take(512).ToArray(); 147 | } 148 | 149 | return ret; 150 | } 151 | 152 | public string GetChipID() 153 | { 154 | var response = SendCommand(new byte[] { 0x06, 0x56, 0x00, 0x00, 0x00, 155 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 512); 156 | 157 | return BitConverter.ToString(response, 0, 6); 158 | } 159 | 160 | public string GetFirmwareVersion() 161 | { 162 | var info = RequestVendorInfo(); 163 | 164 | return info[0x94] + "." + info[0x95].ToString("X02") + "." + info[0x96].ToString("X02"); 165 | } 166 | 167 | public ushort? GetChipType() 168 | { 169 | ushort? ret = null; 170 | var info = RequestVendorInfo(); 171 | 172 | if (info != null) 173 | { 174 | if (info[0x17A] == (byte)'V' && info[0x17B] == (byte)'R') 175 | { 176 | var data = info.Skip(0x17E).Take(2).ToArray(); 177 | ret = (ushort)((data[0] << 8) | data[1]); 178 | } 179 | } 180 | 181 | return ret; 182 | } 183 | 184 | public RunMode GetRunMode() 185 | { 186 | var ret = RunMode.Unknown; 187 | var info = RequestVendorInfo(); 188 | 189 | if (info != null) 190 | { 191 | if (info[0x17A] == (byte)'V' && info[0x17B] == (byte)'R') 192 | { 193 | //TODO: Fix this, this is a dumb way of detecting it 194 | switch (ASCIIEncoding.ASCII.GetString(info.Skip(0xA0).Take(8).ToArray())) 195 | { 196 | case " PRAM ": 197 | ret = RunMode.BootMode; 198 | break; 199 | case " FW BURN": 200 | ret = RunMode.Burner; 201 | break; 202 | case " HV TEST": 203 | ret = RunMode.HardwareVerify; 204 | break; 205 | default: 206 | ret = RunMode.Firmware; 207 | break; 208 | } 209 | } 210 | } 211 | 212 | return ret; 213 | } 214 | 215 | public ulong GetNumLBAs() 216 | { 217 | var response = SendCommand(new byte[] { 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); 218 | ulong ret = response[3]; 219 | ret |= (ulong)((ulong)(response[2] << 8) & 0x0000FF00); 220 | ret |= (ulong)((ulong)(response[1] << 16) & 0x00FF0000); 221 | ret |= (ulong)((ulong)(response[0] << 24) & 0xFF000000); 222 | 223 | return ret + 1; 224 | } 225 | 226 | public void JumpToPRAM() 227 | { 228 | SendCommand(new byte[] { 0x06, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); 229 | } 230 | 231 | public void JumpToBootMode() 232 | { 233 | SendCommand(new byte[] { 0x06, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); 234 | } 235 | 236 | public void TransferFile(byte[] data) 237 | { 238 | TransferFile(data, 0x03, 0x02); 239 | } 240 | 241 | public void TransferFile(byte[] data, byte header, byte body) 242 | { 243 | var size = data.Length - 1024; 244 | 245 | //Send header 246 | SendCommand(new byte[] { 0x06, 0xB1, header, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, data.Take(0x200).ToArray()); 247 | 248 | //Get response 249 | var response = SendCommand(new byte[] { 0x06, 0xB0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); 250 | if (response == null || response[0] != 0x55) 251 | { 252 | throw new InvalidOperationException("Header not accepted"); 253 | } 254 | 255 | //Send body 256 | int address = 0; 257 | while (size > 0) 258 | { 259 | int chunkSize; 260 | if (size > 0x8000) 261 | { 262 | chunkSize = 0x8000; 263 | } 264 | else 265 | { 266 | chunkSize = size; 267 | } 268 | 269 | int cmdAddress = address >> 9; 270 | int cmdChunk = chunkSize >> 9; 271 | SendCommand(new byte[] { 0x06, 0xB1, body, (byte)((cmdAddress >> 8) & 0xFF), (byte)(cmdAddress & 0xFF), 272 | 0x00, 0x00, (byte)((cmdChunk >> 8) & 0xFF), (byte)(cmdChunk & 0xFF), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 273 | data.Skip(address + 0x200).Take(chunkSize).ToArray()); 274 | 275 | //Get response 276 | var r = SendCommand(new byte[] { 0x06, 0xB0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); 277 | if (r == null || r[0] != 0xA5) 278 | { 279 | throw new InvalidOperationException("Body not accepted"); 280 | } 281 | 282 | address += chunkSize; 283 | size -= chunkSize; 284 | } 285 | } 286 | 287 | /// 288 | /// Sends command with no attached data and returns expected response. 289 | /// 290 | /// 291 | /// 292 | /// 293 | public byte[] SendCommand(byte[] cmd, int bytesExpected) 294 | { 295 | return _SendCommand(_handle, cmd, null, bytesExpected); 296 | } 297 | 298 | /// 299 | /// Sends command with no attached data and no response. 300 | /// 301 | /// 302 | public void SendCommand(byte[] cmd) 303 | { 304 | SendCommand(cmd, null); 305 | } 306 | 307 | /// 308 | /// Sends command with attached data and no response. 309 | /// 310 | /// 311 | /// 312 | public void SendCommand(byte[] cmd, byte[] data) 313 | { 314 | _SendCommand(_handle, cmd, data, 0); 315 | } 316 | 317 | /// 318 | /// Closes the connection to the device. 319 | /// 320 | public void Close() 321 | { 322 | if (_handle != null && !_handle.IsClosed) 323 | { 324 | _handle.Close(); 325 | } 326 | } 327 | 328 | private static byte[] _SendCommand(SafeFileHandle handle, byte[] cmd, byte[] data, int bytesExpected) 329 | { 330 | const int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014; 331 | const int TIMEOUT_SECS = 30; 332 | SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER scsi = null; 333 | IntPtr inBuffer = IntPtr.Zero; 334 | byte[] ret = null; 335 | 336 | try 337 | { 338 | scsi = new SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER(); 339 | scsi.sptd.Length = (short)Marshal.SizeOf(scsi.sptd); 340 | scsi.sptd.TimeOutValue = TIMEOUT_SECS; 341 | scsi.sptd.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), "sense"); 342 | scsi.sptd.SenseInfoLength = (byte)scsi.sense.Length; 343 | scsi.sptd.CdbLength = (byte)cmd.Length; 344 | Array.Copy(cmd, scsi.sptd.Cdb, cmd.Length); 345 | scsi.sptd.DataIn = data != null && data.Length > 0 ? SCSI_IOCTL_DATA_OUT : SCSI_IOCTL_DATA_IN; 346 | scsi.sptd.DataTransferLength = data != null && data.Length > 0 ? data.Length : bytesExpected; 347 | scsi.sptd.DataBuffer = Marshal.AllocHGlobal(scsi.sptd.DataTransferLength); 348 | if (data != null && data.Length > 0) 349 | { 350 | Marshal.Copy(data, 0, scsi.sptd.DataBuffer, data.Length); 351 | } 352 | 353 | uint bytesReturned; 354 | inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(scsi)); 355 | var size = (uint)Marshal.SizeOf(scsi); 356 | Marshal.StructureToPtr(scsi, inBuffer, false); 357 | if (!DeviceIoControl(handle.DangerousGetHandle(), IOCTL_SCSI_PASS_THROUGH_DIRECT, 358 | inBuffer, size, inBuffer, size, out bytesReturned, IntPtr.Zero)) 359 | { 360 | //Whoops, do something with the error code 361 | int last = Marshal.GetLastWin32Error(); 362 | throw new InvalidOperationException("DeviceIoControl failed: " + last.ToString("X04")); 363 | } 364 | else 365 | { 366 | if (scsi.sptd.ScsiStatus != 0) 367 | { 368 | //Whoops, do something with the error code 369 | throw new InvalidOperationException("SCSI command failed: " + scsi.sptd.ScsiStatus.ToString("X02")); 370 | } 371 | else 372 | { 373 | //Success, marshal back any data we received 374 | if (scsi.sptd.DataTransferLength > 0) 375 | { 376 | ret = new byte[scsi.sptd.DataTransferLength]; 377 | Marshal.Copy(scsi.sptd.DataBuffer, ret, 0, ret.Length); 378 | } 379 | } 380 | } 381 | } 382 | finally 383 | { 384 | /* Free any unmanaged resources */ 385 | 386 | if (scsi != null && scsi.sptd.DataBuffer != IntPtr.Zero) 387 | { 388 | Marshal.FreeHGlobal(scsi.sptd.DataBuffer); 389 | } 390 | 391 | if (inBuffer != IntPtr.Zero) 392 | { 393 | Marshal.FreeHGlobal(inBuffer); 394 | } 395 | } 396 | 397 | return ret; 398 | } 399 | } 400 | } 401 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/PhisonDo.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | /drive=E /burner="C:\\Users\\Brandon\\Documents\GitHub\\PS2251-03\\BINs\BN03V104M.bin" /firmware="C:\\Users\\Brandon\\Documents\\GitHub\\PS2251-03\\patch\\bin\\patched.bin" 5 | 6 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("PhisonDo")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("PhisonDo")] 13 | [assembly: AssemblyCopyright("Copyright © 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("ebfd9a94-1fd1-4595-a864-a3525ff4c875")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DriveCom/DriveCom/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32.SafeHandles; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | using System.Linq; 7 | using System.Text; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace DriveCom 12 | { 13 | class Startup 14 | { 15 | private const int _WAIT_TIME_MS = 2000; 16 | private static PhisonDevice _device = null; 17 | private static string _burner; 18 | private static string _firmware; 19 | private static string _password; 20 | 21 | public enum Action 22 | { 23 | None, 24 | GetInfo, 25 | SetPassword, 26 | DumpFirmware, 27 | SetBootMode, 28 | SendExecutable, 29 | SendFirmware, 30 | GetNumLBAs 31 | } 32 | 33 | public enum ExitCode 34 | { 35 | Success = 0, 36 | Failure = 1 37 | } 38 | 39 | static void Main(string[] args) 40 | { 41 | try 42 | { 43 | Environment.ExitCode = (int)ExitCode.Success; 44 | 45 | var action = Action.None; 46 | string drive = string.Empty; 47 | 48 | foreach (var arg in args) 49 | { 50 | var parts = arg.TrimStart(new char[] { '/' }).Split(new char[] { '=' }, 51 | StringSplitOptions.RemoveEmptyEntries); 52 | switch (parts[0].ToLower()) 53 | { 54 | case "action": 55 | { 56 | action = (Action)Enum.Parse(typeof(Action), parts[1]); 57 | break; 58 | } 59 | case "drive": 60 | { 61 | drive = parts[1]; 62 | break; 63 | } 64 | case "burner": 65 | { 66 | _burner = parts[1]; 67 | break; 68 | } 69 | case "firmware": 70 | { 71 | _firmware = parts[1]; 72 | break; 73 | } 74 | case "password": 75 | { 76 | _password = parts[1]; 77 | break; 78 | } 79 | default: 80 | { 81 | break; 82 | } 83 | } 84 | } 85 | 86 | if (!string.IsNullOrEmpty(drive)) 87 | { 88 | _OpenDrive(drive); 89 | } 90 | 91 | if (action != Action.None) 92 | { 93 | Console.WriteLine("Action specified: " + action.ToString()); 94 | 95 | switch (action) 96 | { 97 | case Action.DumpFirmware: 98 | { 99 | _DumpFirmware(_firmware); 100 | break; 101 | } 102 | case Action.GetInfo: 103 | { 104 | _GetInfo(); 105 | break; 106 | } 107 | case Action.SendExecutable: 108 | { 109 | _ExecuteImage(_burner); 110 | break; 111 | } 112 | case Action.SendFirmware: 113 | { 114 | _SendFirmware(); 115 | break; 116 | } 117 | case Action.GetNumLBAs: 118 | { 119 | _DisplayLBAs(); 120 | break; 121 | } 122 | case Action.SetBootMode: 123 | { 124 | _device.JumpToBootMode(); 125 | Thread.Sleep(_WAIT_TIME_MS); 126 | break; 127 | } 128 | case Action.SetPassword: 129 | { 130 | _SendPassword(_password); 131 | break; 132 | } 133 | default: 134 | { 135 | throw new ArgumentException("No/invalid action specified"); 136 | } 137 | } 138 | } 139 | else 140 | { 141 | Console.WriteLine("No action specified, entering console."); 142 | 143 | bool exiting = false; 144 | while (!exiting) 145 | { 146 | Console.Write(">"); 147 | var line = Console.ReadLine(); 148 | var @params = line.Split(new char[] { ' ' }); 149 | 150 | try 151 | { 152 | switch (@params[0].ToLower()) 153 | { 154 | case "open": 155 | { 156 | _OpenDrive(@params[1]); 157 | break; 158 | } 159 | case "close": 160 | { 161 | _CloseDrive(); 162 | break; 163 | } 164 | case "mode": 165 | { 166 | _GetInfo(); 167 | break; 168 | } 169 | case "info": 170 | { 171 | var data = _device.RequestVendorInfo(); 172 | Console.WriteLine(string.Format("Info: {0}...", BitConverter.ToString(data, 0, 16))); 173 | break; 174 | } 175 | case "get_num_lbas": 176 | { 177 | _DisplayLBAs(); 178 | break; 179 | } 180 | case "password": 181 | { 182 | _SendPassword(@params[1]); 183 | break; 184 | } 185 | case "dump_xram": 186 | { 187 | var address = 0; 188 | var data = new byte[0xF000]; 189 | for (int i = 0; i < data.Length; i++) 190 | { 191 | var result = _device.SendCommand(new byte[] { 0x06, 0x06, 192 | (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); 193 | data[address] = result[0]; 194 | address++; 195 | } 196 | 197 | File.WriteAllBytes(@params[1], data); 198 | break; 199 | } 200 | case "dump_firmware": 201 | { 202 | _DumpFirmware(@params[1]); 203 | break; 204 | } 205 | case "nand_read": 206 | { 207 | var address = Convert.ToInt32(@params[1], 16); 208 | var size = Convert.ToInt32(@params[2], 16); 209 | var result = _device.SendCommand(new byte[] { 0x06, 0xB2, 0x10, 210 | (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 211 | (byte)((size >> 8) & 0xFF), (byte)(size & 0xFF) }, size * 512); 212 | Console.WriteLine(string.Format("Data: {0}...", BitConverter.ToString(result, 0, 16))); 213 | break; 214 | } 215 | case "boot": 216 | { 217 | _device.JumpToBootMode(); 218 | Thread.Sleep(_WAIT_TIME_MS); 219 | break; 220 | } 221 | case "set_burner": 222 | { 223 | _burner = @params[1]; 224 | break; 225 | } 226 | case "set_firmware": 227 | { 228 | _firmware = @params[1]; 229 | break; 230 | } 231 | case "burner": 232 | { 233 | _ExecuteImage(_burner); 234 | break; 235 | } 236 | case "firmware": 237 | { 238 | _SendFirmware(); 239 | break; 240 | } 241 | case "peek": 242 | { 243 | var address = Convert.ToInt32(@params[1], 16); 244 | var result = _device.SendCommand(new byte[] { 0x06, 0x06, 245 | (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); 246 | Console.WriteLine("Value: " + result[0].ToString("X02")); 247 | break; 248 | } 249 | case "poke": 250 | { 251 | var address = Convert.ToInt32(@params[1], 16); 252 | var value = Convert.ToInt32(@params[2], 16); 253 | _device.SendCommand(new byte[] { 0x06, 0x07, 254 | (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), (byte)value, 0x00, 0x00 }, 1); 255 | break; 256 | } 257 | case "ipeek": 258 | { 259 | var address = Convert.ToInt32(@params[1], 16); 260 | var result = _device.SendCommand(new byte[] { 0x06, 0x08, 261 | (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); 262 | Console.WriteLine("Value: " + result[0].ToString("X02")); 263 | break; 264 | } 265 | case "ipoke": 266 | { 267 | var address = Convert.ToInt32(@params[1], 16); 268 | var value = Convert.ToInt32(@params[2], 16); 269 | _device.SendCommand(new byte[] { 0x06, 0x09, 270 | (byte)(address & 0xFF), (byte)value, 0x00, 0x00 }, 1); 271 | break; 272 | } 273 | case "quit": 274 | case "exit": 275 | { 276 | exiting = true; 277 | break; 278 | } 279 | default: 280 | Console.WriteLine("Invalid command: " + @params[0]); 281 | break; 282 | } 283 | } 284 | catch (Exception ex) 285 | { 286 | Console.WriteLine("ERROR: " + ex.ToString()); 287 | } 288 | } 289 | 290 | Console.WriteLine("Done."); 291 | } 292 | } 293 | catch (Exception ex) 294 | { 295 | Environment.ExitCode = (int)ExitCode.Failure; 296 | 297 | Console.WriteLine("FATAL: " + ex.ToString()); 298 | } 299 | finally 300 | { 301 | if (_device != null) 302 | { 303 | _device.Close(); 304 | } 305 | } 306 | } 307 | 308 | private static void _OpenDrive(string drive) 309 | { 310 | _CloseDrive(); 311 | 312 | _device = new PhisonDevice(drive[0]); 313 | _device.Open(); 314 | } 315 | 316 | private static void _CloseDrive() 317 | { 318 | if (_device != null) 319 | { 320 | _device.Close(); 321 | _device = null; 322 | } 323 | } 324 | 325 | private static void _DisplayLBAs() 326 | { 327 | Console.WriteLine("Number of LBAs: 0x" + _device.GetNumLBAs().ToString("X08")); 328 | } 329 | 330 | private static void _DumpFirmware(string fileName) 331 | { 332 | var address = 0; 333 | var data = new byte[0x32400]; 334 | var header = new byte[] { 0x42, 0x74, 0x50, 0x72, 0x61, 0x6D, 0x43, 0x64, 335 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x0B, 0x18 }; 336 | Array.Copy(header, 0, data, 0, header.Length); 337 | while (address * 0x200 < data.Length) 338 | { 339 | var length = Math.Min(0x40 * 512, (data.Length - 0x400) - (address * 0x200)); 340 | var temp = length / 512; 341 | var result = _device.SendCommand(new byte[] { 0x06, 0xB2, 0x10, 342 | (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 343 | (byte)((temp >> 8) & 0xFF), (byte)(temp & 0xFF) }, length); 344 | Array.Copy(result.Take(length).ToArray(), 0, data, 0x200 + address * 512, length); 345 | address += 0x40; 346 | } 347 | 348 | var footer = new byte[] { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6D, 349 | 0x70, 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x00, 0x03, 0x01, 0x00, 0x10, 0x01, 0x04, 0x10, 0x42 }; 350 | Array.Copy(footer, 0, data, data.Length - 0x200, footer.Length); 351 | File.WriteAllBytes(fileName, data); 352 | } 353 | 354 | private static void _SendPassword(string password) 355 | { 356 | var data = new byte[0x200]; 357 | var pw = ASCIIEncoding.ASCII.GetBytes(password); 358 | Array.Copy(pw, 0, data, 0x10, pw.Length); 359 | _device.SendCommand(new byte[] { 0x0E, 0x00, 0x01, 0x55, 0xAA, 360 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, data); 361 | } 362 | 363 | private static void _SendFirmware() 364 | { 365 | var mode = _GetInfo(); 366 | if (mode != PhisonDevice.RunMode.Burner) 367 | { 368 | if (mode != PhisonDevice.RunMode.BootMode) 369 | { 370 | Console.WriteLine("Switching to boot mode..."); 371 | _device.JumpToBootMode(); 372 | Thread.Sleep(_WAIT_TIME_MS); 373 | } 374 | 375 | _ExecuteImage(_burner); 376 | } 377 | 378 | _RunFirmware(_firmware); 379 | } 380 | 381 | private static PhisonDevice.RunMode _GetInfo() 382 | { 383 | Console.WriteLine("Gathering information..."); 384 | Console.WriteLine("Reported chip type: " + _device.GetChipType().GetValueOrDefault().ToString("X04")); 385 | Console.WriteLine("Reported chip ID: " + _device.GetChipID()); 386 | Console.WriteLine("Reported firmware version: " + _device.GetFirmwareVersion()); 387 | 388 | var ret = _device.GetRunMode(); 389 | Console.WriteLine("Mode: " + ret.ToString()); 390 | 391 | return ret; 392 | } 393 | 394 | private static void _ExecuteImage(string fileName) 395 | { 396 | //Read image 397 | var file = new FileStream(fileName, FileMode.Open); 398 | var fileData = new byte[file.Length]; 399 | file.Read(fileData, 0, fileData.Length); 400 | file.Close(); 401 | 402 | //Load it 403 | _device.TransferFile(fileData); 404 | _device.JumpToPRAM(); 405 | 406 | //Wait a little bit 407 | Thread.Sleep(_WAIT_TIME_MS); 408 | } 409 | 410 | private static void _RunFirmware(string fileName) 411 | { 412 | //Get file data 413 | var fw = new FileStream(fileName, FileMode.Open); 414 | var data = new byte[fw.Length]; 415 | fw.Read(data, 0, data.Length); 416 | fw.Close(); 417 | 418 | //TODO: Find out what this actually does... 419 | //Console.WriteLine("Sending scary B7 command (takes several seconds)..."); 420 | //_device.SendCommand(new byte[] { 0x06, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); 421 | 422 | Console.WriteLine("Rebooting..."); 423 | _device.JumpToBootMode(); 424 | Thread.Sleep(_WAIT_TIME_MS); 425 | 426 | Console.WriteLine("Sending firmware..."); 427 | _device.TransferFile(data, 0x01, 0x00); 428 | var ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); 429 | Thread.Sleep(_WAIT_TIME_MS); 430 | _device.TransferFile(data, 0x03, 0x02); 431 | ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); 432 | Thread.Sleep(_WAIT_TIME_MS); 433 | ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); 434 | Thread.Sleep(_WAIT_TIME_MS); 435 | ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); 436 | Thread.Sleep(_WAIT_TIME_MS); 437 | 438 | Console.WriteLine("Executing..."); 439 | _device.JumpToPRAM(); 440 | Thread.Sleep(_WAIT_TIME_MS); 441 | 442 | //Display new mode, if we can actually get it 443 | Console.WriteLine("Mode: " + _device.GetRunMode().ToString()); 444 | } 445 | } 446 | } 447 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbedPayload", "EmbedPayload\EmbedPayload.csproj", "{E2381629-180B-44DE-8702-B63B4699A587}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {E2381629-180B-44DE-8702-B63B4699A587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {E2381629-180B-44DE-8702-B63B4699A587}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {E2381629-180B-44DE-8702-B63B4699A587}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {E2381629-180B-44DE-8702-B63B4699A587}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/EmbedPayload/EmbedPayload.v11.suo -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload.vshost.exe.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload/EmbedPayload.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {E2381629-180B-44DE-8702-B63B4699A587} 8 | Exe 9 | Properties 10 | EmbedPayload 11 | EmbedPayload 12 | v4.5 13 | 512 14 | 15 | 16 | AnyCPU 17 | true 18 | full 19 | false 20 | ..\..\tools\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | AnyCPU 27 | pdbonly 28 | true 29 | ..\..\tools\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 58 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("EmbedPayload")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Toshiba")] 12 | [assembly: AssemblyProduct("EmbedPayload")] 13 | [assembly: AssemblyCopyright("Copyright © Toshiba 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5cd1f91a-6190-490e-a5c8-6d200a7e00db")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /EmbedPayload/EmbedPayload/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace EmbedPayload 9 | { 10 | class Startup 11 | { 12 | public enum ExitCode 13 | { 14 | Success = 0, 15 | Failure = 1 16 | } 17 | 18 | static void Main(string[] args) 19 | { 20 | if (args.Length != 2) 21 | { 22 | Console.WriteLine("Usage: [payload BIN] [firmware image]"); 23 | return; 24 | } 25 | 26 | try 27 | { 28 | //Assume success at first 29 | Environment.ExitCode = (int)ExitCode.Success; 30 | 31 | //Read all bytes from input file 32 | var payload = File.ReadAllBytes(args[0]); 33 | 34 | //Read all bytes from output file: 35 | var stream = new FileStream(args[1], FileMode.Open, FileAccess.ReadWrite); 36 | var header = new byte[0x200]; 37 | stream.Read(header, 0, header.Length); 38 | var data = new byte[0x6000]; 39 | stream.Read(data, 0, data.Length); 40 | 41 | // Look for 0x12345678 42 | var signature = new byte[] { 0x12, 0x34, 0x56, 0x78 }; 43 | int? address = null; 44 | for (int i = 0; i < data.Length; i++) 45 | { 46 | bool match = true; 47 | for (int j = 0; j < signature.Length; j++) 48 | { 49 | if (data[i + j] != signature[j]) 50 | { 51 | match = false; 52 | break; 53 | } 54 | } 55 | 56 | if (match) 57 | { 58 | address = i; 59 | break; 60 | } 61 | } 62 | 63 | // When found, overwrite with input data 64 | if (address.HasValue) 65 | { 66 | if ((0x200 + address.Value) >= 0x6000) 67 | { 68 | throw new InvalidOperationException("Insufficient memory to inject file!"); 69 | } 70 | 71 | stream.Seek(0x200 + address.Value, SeekOrigin.Begin); 72 | stream.Write(payload, 0, payload.Length); 73 | 74 | //Save output file back out 75 | stream.Close(); 76 | Console.WriteLine("File updated."); 77 | } 78 | else 79 | { 80 | Console.WriteLine("Signature not found!"); 81 | } 82 | } 83 | catch (Exception ex) 84 | { 85 | //Uh-oh 86 | Environment.ExitCode = (int)ExitCode.Failure; 87 | 88 | Console.WriteLine("FATAL: " + ex.ToString()); 89 | } 90 | } 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Injector/Injector.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Express 2012 for Windows Desktop 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Injector", "Injector\Injector.csproj", "{41480B6F-9051-43D1-9484-30A265D09D5D}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {41480B6F-9051-43D1-9484-30A265D09D5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {41480B6F-9051-43D1-9484-30A265D09D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {41480B6F-9051-43D1-9484-30A265D09D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {41480B6F-9051-43D1-9484-30A265D09D5D}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | EndGlobal 21 | -------------------------------------------------------------------------------- /Injector/Injector.v11.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/Injector/Injector.v11.suo -------------------------------------------------------------------------------- /Injector/Injector/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Injector/Injector/DoPatch.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | /firmware="C:\\Users\\Brandon\\Documents\\GitHub\\PS2251-03\\BINs\\FW03FF01V10353M.BIN" /basecode="C:\\Users\\Brandon\\Documents\\GitHub\\PS2251-03\\patch\\bin\\output.bin" /action=FindFreeBlocks /output="C:\\Users\\Brandon\\Documents\\GitHub\\PS2251-03\\patch\\bin\\patched.bin" /baserst="C:\\Users\\Brandon\\Documents\\GitHub\\PS2251-03\\patch\\bin\\main.rst" 5 | 6 | -------------------------------------------------------------------------------- /Injector/Injector/FirmwareImage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Injector 9 | { 10 | public class FirmwareImage 11 | { 12 | private string _fileName; 13 | private byte[] _header; 14 | private Dictionary _sections; 15 | private byte[] _footer; 16 | 17 | public FirmwareImage(string fileName) 18 | { 19 | _fileName = fileName; 20 | _header = new byte[0x200]; 21 | _sections = new Dictionary(); 22 | _sections.Add(FirmwareSection.Base, new byte[0x6000]); 23 | } 24 | 25 | public byte[] GetSection(FirmwareSection section) 26 | { 27 | byte[] ret = null; 28 | 29 | if (_sections.ContainsKey(section)) 30 | { 31 | ret = _sections[section]; 32 | } 33 | 34 | return ret; 35 | } 36 | 37 | public void Open() 38 | { 39 | FirmwareSection i = 0; 40 | 41 | //Get the header and base page 42 | var stream = new FileStream(_fileName, FileMode.Open); 43 | var @base = GetSection(FirmwareSection.Base); 44 | stream.Read(_header, 0, _header.Length); 45 | stream.Read(@base, 0, @base.Length); 46 | 47 | //Read in all the sections 48 | while ((stream.Length - stream.Position) > 0x200) 49 | { 50 | var data = new byte[0x4000]; 51 | stream.Read(data, 0, data.Length); 52 | _sections.Add(i++, data); 53 | } 54 | 55 | //If we have a footer, read it in 56 | if ((stream.Length - stream.Position) == 0x200) 57 | { 58 | _footer = new byte[0x200]; 59 | stream.Read(_footer, 0, _footer.Length); 60 | } 61 | 62 | //All done 63 | stream.Close(); 64 | } 65 | 66 | public bool FindPattern(byte?[] pattern, out FirmwareSection section, out int address) 67 | { 68 | return FindPattern(pattern, 0, out section, out address); 69 | } 70 | 71 | public bool FindPattern(byte?[] pattern, int startingOffset, out FirmwareSection section, out int address) 72 | { 73 | bool ret = false; 74 | section = FirmwareSection.Base; 75 | address = 0; 76 | 77 | foreach (var s in _sections) 78 | { 79 | for (int i = startingOffset; i < s.Value.Length; i++) 80 | { 81 | bool match = true; 82 | for (int j = 0; j < pattern.Length; j++) 83 | { 84 | if (((i + j) >= s.Value.Length) || 85 | ((s.Value[i + j] != pattern[j]) && (pattern[j].HasValue))) 86 | { 87 | match = false; 88 | break; 89 | } 90 | } 91 | 92 | if (match) 93 | { 94 | section = s.Key; 95 | address = i; 96 | ret = true; 97 | break; 98 | } 99 | } 100 | 101 | if (ret) 102 | { 103 | break; 104 | } 105 | } 106 | 107 | return ret; 108 | } 109 | 110 | public int FindLastFreeChunk(FirmwareSection section) 111 | { 112 | int ret = -1; 113 | 114 | if (_sections.ContainsKey(section)) 115 | { 116 | var data = _sections[section]; 117 | var repeating = data[data.Length - 1]; 118 | ret = data.Length - 2; 119 | 120 | while (data[ret] == repeating) 121 | { 122 | ret--; 123 | if (ret < 0) 124 | { 125 | break; 126 | } 127 | } 128 | } 129 | 130 | return ++ret; 131 | } 132 | 133 | public void Save(string fileName) 134 | { 135 | var output = new FileStream(fileName, FileMode.Create); 136 | output.Write(_header, 0, _header.Length); 137 | foreach (var section in _sections.OrderBy(t => t.Key)) 138 | { 139 | output.Write(section.Value, 0, section.Value.Length); 140 | } 141 | 142 | if (_footer != null) 143 | { 144 | output.Write(_footer, 0, _footer.Length); 145 | } 146 | 147 | output.Close(); 148 | } 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /Injector/Injector/FirmwareSection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Injector 8 | { 9 | public enum FirmwareSection 10 | { 11 | None = -2, 12 | Base = -1, 13 | Section0 = 0x00, 14 | Section1 = 0x01, 15 | Section2 = 0x02, 16 | Section3 = 0x03, 17 | Section4 = 0x04, 18 | Section5 = 0x05, 19 | Section6 = 0x06, 20 | Section7 = 0x07, 21 | Section8 = 0x08, 22 | Section9 = 0x09, 23 | SectionA = 0x0A, 24 | SectionB = 0x0B, 25 | SectionC = 0x0C, 26 | SectionD = 0x0D, 27 | SectionE = 0x0E, 28 | SectionF = 0x0F 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Injector/Injector/Injector.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {41480B6F-9051-43D1-9484-30A265D09D5D} 8 | Exe 9 | Properties 10 | Injector 11 | Injector 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | ..\..\tools\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | ..\..\tools\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 61 | -------------------------------------------------------------------------------- /Injector/Injector/Injector.csproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | /firmware=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\FW03FF01V10353M.BIN /output=free.txt /action=FindFreeBlock 5 | 6 | -------------------------------------------------------------------------------- /Injector/Injector/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DoPatch")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Toshiba")] 12 | [assembly: AssemblyProduct("DoPatch")] 13 | [assembly: AssemblyCopyright("Copyright © Toshiba 2014")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("16a14751-01cb-4cb0-a3d1-7835d24f4711")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Injector/Injector/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using System.Security.Cryptography; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Injector 11 | { 12 | class Startup 13 | { 14 | private static string _firmwareImage; 15 | private static string _outputFile; 16 | private static FirmwareSection _section = FirmwareSection.None; 17 | private static Dictionary _codeFiles; 18 | private static Dictionary _rstFiles; 19 | 20 | internal enum Action 21 | { 22 | None, 23 | GenerateHFile, 24 | FindFreeBlock, 25 | ApplyPatches 26 | } 27 | 28 | internal enum ExitCode 29 | { 30 | Success = 0, 31 | Failure = 1 32 | } 33 | 34 | static void Main(string[] args) 35 | { 36 | try 37 | { 38 | _codeFiles = new Dictionary(); 39 | _rstFiles = new Dictionary(); 40 | 41 | //Assume success to start with 42 | Environment.ExitCode = (int)ExitCode.Success; 43 | 44 | var action = Action.None; 45 | 46 | //Parse command line arguments 47 | foreach (var arg in args) 48 | { 49 | var parts = arg.TrimStart(new char[] { '/' }).Split(new char[] { '=' }, 50 | StringSplitOptions.RemoveEmptyEntries); 51 | switch (parts[0].ToLower()) 52 | { 53 | case "action": 54 | { 55 | action = (Action)Enum.Parse(typeof(Action), parts[1]); 56 | Console.WriteLine("Action: " + action.ToString()); 57 | break; 58 | } 59 | case "section": 60 | { 61 | _section = (FirmwareSection)Enum.Parse(typeof(FirmwareSection), parts[1]); 62 | Console.WriteLine("Section: " + _section.ToString()); 63 | break; 64 | } 65 | case "firmware": 66 | { 67 | _firmwareImage = parts[1]; 68 | Console.WriteLine("Firmware image: " + _firmwareImage); 69 | _CheckFirmwareImage(); 70 | break; 71 | } 72 | case "output": 73 | { 74 | _outputFile = parts[1]; 75 | Console.WriteLine("Output file: " + _outputFile); 76 | break; 77 | } 78 | default: 79 | { 80 | _ParseFileNames(ref _codeFiles, "code", parts[0], parts[1]); 81 | _ParseFileNames(ref _rstFiles, "rst", parts[0], parts[1]); 82 | break; 83 | } 84 | } 85 | } 86 | 87 | //Firmware image file name is always required 88 | if (string.IsNullOrEmpty(_firmwareImage)) 89 | { 90 | throw new ArgumentException("No/Invalid firmware image file name specified"); 91 | } 92 | 93 | switch (action) 94 | { 95 | case Action.GenerateHFile: 96 | { 97 | if (string.IsNullOrEmpty(_outputFile)) 98 | { 99 | throw new ArgumentException("No/Invalid output file name specified"); 100 | } 101 | 102 | Console.WriteLine("Generating .h file..."); 103 | 104 | _GenerateHFile(); 105 | break; 106 | } 107 | case Action.ApplyPatches: 108 | { 109 | //Check required arguments for this action 110 | 111 | if (string.IsNullOrEmpty(_outputFile)) 112 | { 113 | throw new ArgumentException("No/Invalid output file name specified"); 114 | } 115 | 116 | if (_codeFiles.Count == 0) 117 | { 118 | throw new ArgumentException("No code file name(s) specified"); 119 | } 120 | 121 | if (_rstFiles.Count == 0) 122 | { 123 | throw new ArgumentException("No/Invalid RST file name specified"); 124 | } 125 | 126 | Console.WriteLine("Applying patches..."); 127 | _ApplyPatches(); 128 | break; 129 | } 130 | case Action.FindFreeBlock: 131 | { 132 | //Check required arguments for this action 133 | if (_section == FirmwareSection.None) 134 | { 135 | throw new ArgumentException("No/Invalid section specified"); 136 | } 137 | 138 | Console.WriteLine("Retriving free space..."); 139 | _GetFreeSpaceToFile(); 140 | break; 141 | } 142 | default: 143 | throw new ArgumentException("No/Invalid action specified"); 144 | } 145 | 146 | Console.WriteLine("Done."); 147 | } 148 | catch (Exception ex) 149 | { 150 | //Uh-oh... 151 | Environment.ExitCode = (int)ExitCode.Failure; 152 | 153 | var asm = System.Reflection.Assembly.GetExecutingAssembly(); 154 | var asmName = asm.GetName(); 155 | Console.WriteLine(asmName.Name + " v" + asmName.Version.ToString(3)); 156 | Console.WriteLine("Actions:"); 157 | Console.WriteLine("\tGenerateHFile\tGenerates C .h file of common XRAM & function equates."); 158 | Console.WriteLine("\tFindFreeBlock\tWrites amount of free space for a section to file."); 159 | Console.WriteLine("\tApplyPatches\tApplies available patches from code into firmware image."); 160 | Console.WriteLine(); 161 | Console.WriteLine("FATAL: " + ex.ToString()); 162 | } 163 | } 164 | 165 | private static void _CheckFirmwareImage() 166 | { 167 | var md5 = new MD5CryptoServiceProvider(); 168 | var verified = new List(); 169 | verified.Add("4C4C0001EC83102C4627D271FF8362A2"); 170 | 171 | var hash = BitConverter.ToString(md5.ComputeHash(File.ReadAllBytes(_firmwareImage))) 172 | .Replace("-", string.Empty); 173 | if (!verified.Contains(hash)) 174 | { 175 | Console.WriteLine("WARNING! This firmware version has not been " + 176 | "verified to work with these patches."); 177 | } 178 | } 179 | 180 | private static void _ParseFileNames(ref Dictionary files, 181 | string suffix, string name, string value) 182 | { 183 | if (name.ToLower().EndsWith(suffix)) 184 | { 185 | var section = FirmwareSection.Base; 186 | int s; 187 | 188 | if (int.TryParse(name.Substring(0, name.Length - suffix.Length), out s)) 189 | { 190 | section = (FirmwareSection)s; 191 | } 192 | 193 | files.Add(section, value); 194 | Console.WriteLine(suffix + " " + section.ToString() + " file: " + value); 195 | } 196 | } 197 | 198 | private static Dictionary _GetAddressMap(string fileName) 199 | { 200 | //Read in RST file and its label<->address map 201 | var addressMap = new Dictionary(); 202 | var ret = new Dictionary(); 203 | var rst = new StreamReader(fileName, ASCIIEncoding.ASCII); 204 | 205 | while (true) 206 | { 207 | var line = rst.ReadLine(); 208 | if (line == null) 209 | { 210 | break; 211 | } 212 | 213 | if (line.EndsWith(":")) 214 | { 215 | var parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); 216 | var label = parts[parts.Length - 1].TrimEnd(':'); 217 | var address = parts[0]; 218 | 219 | if (label.StartsWith("_")) 220 | { 221 | ret.Add(label, Convert.ToInt32(address, 16)); 222 | } 223 | } 224 | } 225 | 226 | rst.Close(); 227 | 228 | return ret; 229 | } 230 | 231 | private static void _GenerateHFile() 232 | { 233 | var stream = new StreamWriter(_outputFile); 234 | 235 | //Read in firmware image 236 | var image = new FirmwareImage(_firmwareImage); 237 | image.Open(); 238 | 239 | var pattern = new byte?[] { 0x90, 0xF0, 0xB8, 0xE0, //mov DPTR, #0xF0B8 \ movx a, @DPTR 240 | 0x90, null, null, 0xF0, //mov DPTR, #0x???? \ movx @DPTR, a 241 | 0x90, 0xF0, 0xB9, 0xE0 }; //mov DPTR, #0xF0B9 \ movx a, @DPTR \ movx DPTR, #0x???? 242 | FirmwareSection section; 243 | int address; 244 | if (image.FindPattern(pattern, out section, out address)) 245 | { 246 | var a = image.GetSection(section)[address + 5] << 8; 247 | a |= image.GetSection(section)[address + 6]; 248 | 249 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", a.ToString("X04"), "bmRequestType")); 250 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", (a + 1).ToString("X04"), "bRequest")); 251 | } 252 | 253 | pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx a, @DPTR 254 | 0xB4, 0x28 }; //cjne A, #0x28, ???? 255 | if (image.FindPattern(pattern, out section, out address)) 256 | { 257 | var a = image.GetSection(section)[address + 1] << 8; 258 | a |= image.GetSection(section)[address + 2]; 259 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[16];", a.ToString("X04"), "scsi_cdb")); 260 | 261 | stream.WriteLine(string.Format("#define {0} 0x{1}", "DEFAULT_READ_SECTOR_HANDLER", (address + 7).ToString("X04"))); 262 | pattern = new byte?[] { 0x90, (byte)((a >> 8) & 0xFF), (byte)(a & 0xFF), //mov DPTR, #scsi_tag 263 | 0xE0, 0x12 }; //mvox A, @DPTR \ lcall 0x???? 264 | if (image.FindPattern(pattern, address, out section, out address)) 265 | { 266 | stream.WriteLine(string.Format("#define {0} 0x{1}", "DEFAULT_CDB_HANDLER", address.ToString("X04"))); 267 | } 268 | } 269 | 270 | pattern = new byte?[] { 0x90, 0xF2, 0x1C, //mov DPTR, #0xF21C 271 | 0x74, 0x55, 0xF0, //mov A, #0x55 \ movx @DPTR, A 272 | 0x74, 0x53, 0xF0, //mov A, #0x53 \ movx @DPTR, A 273 | 0x74, 0x42, 0xF0, //mov A, #0x42 \ movx @DPTR, A 274 | 0x74, 0x53, 0xF0, //mov A, #0x53 \ movx @DPTR, A 275 | 0x90 }; //mov DPTR, #0x???? 276 | if (image.FindPattern(pattern, out section, out address)) 277 | { 278 | var a = image.GetSection(section)[address + pattern.Length] << 8; 279 | a |= image.GetSection(section)[address + pattern.Length + 1]; 280 | 281 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[4];", (a - 3).ToString("X04"), "scsi_tag")); 282 | } 283 | 284 | pattern = new byte?[] { 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, //push ACC \ push DPH \ push DPL 285 | 0x90, 0xF0, 0x20, 0xE0, //mov DPTR, #0xF020 \ movx A, @DPTR 286 | 0x30, 0xE1, null, //jnb ACC.1, ???? 287 | 0x12, null, null, 0x90 }; //lcall ???? \ mov DPTR, #0x???? 288 | if (image.FindPattern(pattern, out section, out address)) 289 | { 290 | var a = image.GetSection(section)[address + 17] << 8; 291 | a |= image.GetSection(section)[address + 18]; 292 | 293 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", a.ToString("X04"), "FW_EPIRQ")); 294 | } 295 | 296 | stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[1024];", "B000", "EPBUF")); 297 | 298 | stream.Close(); 299 | } 300 | 301 | private static void _GetFreeSpaceToFile() 302 | { 303 | //Read in firmware image 304 | var image = new FirmwareImage(_firmwareImage); 305 | image.Open(); 306 | 307 | File.WriteAllText(_outputFile, "0x" + image.FindLastFreeChunk(_section).ToString("X04")); 308 | } 309 | 310 | private static void _ApplyPatches() 311 | { 312 | //Read in firmware image 313 | var image = new FirmwareImage(_firmwareImage); 314 | image.Open(); 315 | 316 | //Read in the RST files 317 | var maps = new Dictionary>(); 318 | foreach (var file in _rstFiles) 319 | { 320 | maps.Add(file.Key, _GetAddressMap(file.Value)); 321 | } 322 | 323 | //Find how much free space is left on each page 324 | var emptyStart = new Dictionary(); 325 | for (FirmwareSection i = FirmwareSection.Base; i < FirmwareSection.SectionF; i++) 326 | { 327 | emptyStart.Add(i, image.FindLastFreeChunk(i)); 328 | } 329 | 330 | //Embed our code files into the firmware image 331 | foreach (var file in _codeFiles) 332 | { 333 | var code = File.ReadAllBytes(file.Value); 334 | Array.Copy(code, 0, image.GetSection(file.Key), emptyStart[file.Key], code.Length); 335 | emptyStart[file.Key] += code.Length; 336 | } 337 | 338 | //Find the off-page call stubs 339 | var stubs = new Dictionary(); 340 | int saddr = 0; 341 | var spattern = new byte?[] { 0xC0, 0x5B, 0x74, 0x08, //push RAM_5B \ mov A, #8 342 | 0xC0, 0xE0, 0xC0, 0x82, 0xC0, 0x83, //push ACC \ push DPL \ push DPH 343 | 0x75, 0x5B }; //mov RAM_5B, #0x?? 344 | FirmwareSection fs; 345 | for (FirmwareSection i = FirmwareSection.Section0; i <= FirmwareSection.SectionF; i++) 346 | { 347 | if (image.FindPattern(spattern, saddr, out fs, out saddr)) 348 | { 349 | stubs.Add(i, saddr); 350 | saddr += spattern.Length; //move ahead so we can find the next stub 351 | } 352 | } 353 | 354 | //Hook into control request handling 355 | foreach (var map in maps) 356 | { 357 | if (map.Value.ContainsKey("_HandleControlRequest")) 358 | { 359 | var address = map.Value["_HandleControlRequest"]; 360 | var pattern = new byte?[] { 0x12, null, null, //lcall #0x???? 361 | 0x90, 0xFE, 0x82, 0xE0, //mov DPTR, #0xFE82 \ movx A, @DPTR 362 | 0x54, 0xEF, 0xF0 }; //anl A, #0xEF \ movx @DPTR, A 363 | FirmwareSection s; 364 | int a; 365 | if (image.FindPattern(pattern, out s, out a)) 366 | { 367 | a = (image.GetSection(s)[a + 1] << 8) | image.GetSection(s)[a + 2]; 368 | 369 | image.GetSection(s)[a + 1] = (byte)((address >> 8) & 0xFF); 370 | image.GetSection(s)[a + 2] = (byte)(address & 0xFF); 371 | if (map.Key != FirmwareSection.Base) 372 | { 373 | image.GetSection(s)[a + 4] = (byte)((stubs[map.Key] >> 8) & 0xFF); 374 | image.GetSection(s)[a + 5] = (byte)(stubs[map.Key] & 0xFF); 375 | } 376 | } 377 | break; 378 | } 379 | } 380 | 381 | //Replace the EP interrupt vector, handling all incoming and outgoing non-control data 382 | foreach (var map in maps) 383 | { 384 | //This part must be on the base page 385 | if (map.Value.ContainsKey("_EndpointInterrupt")) 386 | { 387 | var address = map.Value["_EndpointInterrupt"]; 388 | var s = image.GetSection(FirmwareSection.Base); 389 | s[0x0014] = (byte)((address >> 8) & 0xFF); 390 | s[0x0015] = (byte)(address & 0xFF); 391 | } 392 | 393 | if (map.Value.ContainsKey("_HandleEndpointInterrupt")) 394 | { 395 | //Find the base page location to patch 396 | var pattern = new byte?[] { 0x30, 0xE1, null, //jnb ACC.1, #0x???? 397 | 0x12, null, null, //lcall #0x???? 398 | 0x90, 0xFE, 0x82, 0xE0, //mov DPTR, #0xFE82 \ movx A, @DPTR 399 | 0x54, 0xEF, 0xF0 }; //anl A, #0xEF \ movx @DPTR, A 400 | FirmwareSection ps; 401 | int pa; 402 | if (image.FindPattern(pattern, out ps, out pa)) 403 | { 404 | //Create off-page stub for this if necessary 405 | var address = map.Value["_HandleEndpointInterrupt"]; 406 | var stubAddress = address; 407 | if (map.Key != FirmwareSection.Base) 408 | { 409 | stubAddress = emptyStart[FirmwareSection.Base]; 410 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; 411 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); 412 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); 413 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; 414 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); 415 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); 416 | } 417 | 418 | //Apply the patch 419 | var s = image.GetSection(ps); 420 | s[pa + 0] = 0x60; 421 | s[pa + 1] = 0x0B; 422 | s[pa + 2] = 0x00; 423 | s[pa + 4] = (byte)((stubAddress >> 8) & 0xFF); 424 | s[pa + 5] = (byte)(stubAddress & 0xFF); 425 | for (int i = 0; i < 7; i++) 426 | { 427 | s[pa + 6 + i] = 0x00; 428 | } 429 | } 430 | } 431 | } 432 | 433 | //Apply CDB-handling code 434 | foreach (var map in maps) 435 | { 436 | if (map.Value.ContainsKey("_HandleCDB")) 437 | { 438 | var pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx a, @DPTR 439 | 0xB4, 0x28 }; //cjne A, #0x28, ???? 440 | FirmwareSection ps; 441 | int pa; 442 | if (image.FindPattern(pattern, out ps, out pa)) 443 | { 444 | //Create off-page stub for this if necessary 445 | var address = map.Value["_HandleCDB"]; 446 | var stubAddress = address; 447 | if (map.Key != FirmwareSection.Base) 448 | { 449 | stubAddress = emptyStart[FirmwareSection.Base]; 450 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; 451 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); 452 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); 453 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; 454 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); 455 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); 456 | } 457 | 458 | //Apply the patch 459 | var s = image.GetSection(FirmwareSection.Base); 460 | s[pa + 0] = 0x02; 461 | s[pa + 1] = (byte)((stubAddress >> 8) & 0xFF); 462 | s[pa + 2] = (byte)(stubAddress & 0xFF); 463 | } 464 | } 465 | } 466 | 467 | //Add our own code to the infinite loop 468 | foreach (var map in maps) 469 | { 470 | if (map.Value.ContainsKey("_LoopDo")) 471 | { 472 | var pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx A, @DPTR 473 | 0xB4, 0x01, null, //cjne A, #1, #0x???? 474 | 0x90, 0xF0, 0x79 }; //mov DPTR, #0xF079 475 | FirmwareSection ps; 476 | int pa; 477 | if (image.FindPattern(pattern, out ps, out pa)) 478 | { 479 | //Create off-page stub for this if necessary 480 | var address = map.Value["_LoopDo"]; 481 | var stubAddress = address; 482 | if (map.Key != FirmwareSection.Base) 483 | { 484 | stubAddress = emptyStart[FirmwareSection.Base]; 485 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; 486 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); 487 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); 488 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; 489 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); 490 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); 491 | } 492 | 493 | var s = image.GetSection(ps); 494 | var loopDoStart = emptyStart[FirmwareSection.Base]; 495 | s[emptyStart[FirmwareSection.Base]++] = 0x12; 496 | s[emptyStart[FirmwareSection.Base]++] = (byte)((stubAddress >> 8) & 0xFF); 497 | s[emptyStart[FirmwareSection.Base]++] = (byte)(stubAddress & 0xFF); 498 | s[emptyStart[FirmwareSection.Base]++] = 0x90; 499 | s[emptyStart[FirmwareSection.Base]++] = image.GetSection(ps)[pa + 1]; 500 | s[emptyStart[FirmwareSection.Base]++] = image.GetSection(ps)[pa + 2]; 501 | s[emptyStart[FirmwareSection.Base]++] = 0x22; 502 | s[pa + 0] = 0x12; 503 | s[pa + 1] = (byte)((loopDoStart >> 8) & 0xFF); 504 | s[pa + 2] = (byte)(loopDoStart & 0xFF); 505 | } 506 | } 507 | } 508 | 509 | //Apply password patch code 510 | foreach (var map in maps) 511 | { 512 | if (map.Value.ContainsKey("_PasswordReceived")) 513 | { 514 | var pattern = new byte?[] { 0x90, 0xF2, 0x4C, 0xF0, 0xA3, //mov DPTR, #0xF24C \ movx @DPTR, A \ inc DPTR 515 | 0xC0, 0x83, 0xC0, 0x82, 0x12, //push DPH \ push DPL 516 | null, null, 0xD0, 0x82, 0xD0, 0x83, 0xF0, //lcall #0x???? \ pop DPL \ pop DPH \ movx @DPTR, A 517 | 0x90, 0xF2, 0x53, 0x74, 0x80, 0xF0, //mov DPTR, #0xF253 \ mov A, #0x80 \ movx @DPTR, A 518 | 0x90, 0xF2, 0x53, 0xE0, //mov DPTR, #0xF253 \ movx A, @DPTR 519 | 0x30, 0xE7, null, //jnb ACC.7, #0x???? 520 | 0x12, null, null, 0x40, null, //lcall #0x???? \ jc #0x???? 521 | 0x12, null, null, 0x7F, 0x00, 0x22 }; //lcall #0x???? \ mov R7, #0 \ ret 522 | FirmwareSection ps; 523 | int pa; 524 | if (image.FindPattern(pattern, out ps, out pa)) 525 | { 526 | //Create off-page stub for this if necessary 527 | var address = map.Value["_PasswordReceived"]; 528 | var stubAddress = address; 529 | if (map.Key != FirmwareSection.Base) 530 | { 531 | stubAddress = emptyStart[FirmwareSection.Base]; 532 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; 533 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); 534 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); 535 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; 536 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); 537 | image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); 538 | } 539 | 540 | //Apply the patch 541 | pa += 0x24; 542 | var passRecvdStart = emptyStart[ps] + (ps == FirmwareSection.Base ? 0x0000 : 0x5000); 543 | image.GetSection(ps)[emptyStart[ps]++] = 0x12; 544 | image.GetSection(ps)[emptyStart[ps]++] = image.GetSection(ps)[pa + 0]; 545 | image.GetSection(ps)[emptyStart[ps]++] = image.GetSection(ps)[pa + 1]; 546 | image.GetSection(ps)[emptyStart[ps]++] = 0x02; 547 | image.GetSection(ps)[emptyStart[ps]++] = (byte)((stubAddress >> 8) & 0xFF); 548 | image.GetSection(ps)[emptyStart[ps]++] = (byte)(stubAddress & 0xFF); 549 | image.GetSection(ps)[pa + 0] = (byte)((passRecvdStart >> 8) & 0xFF); 550 | image.GetSection(ps)[pa + 1] = (byte)(passRecvdStart & 0xFF); 551 | } 552 | } 553 | } 554 | 555 | //Write the resulting file out 556 | image.Save(_outputFile); 557 | } 558 | } 559 | } 560 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Adam Caudill, Brandon Wilson 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Phison 2251-03 (2303) Custom Firmware & Existing Firmware Patches 2 | ======== 3 | 4 | This repository contains the following items: 5 | - `DriveCom` -- PC C# application to communicate with Phison drives. 6 | - `EmbedPayload` -- PC C# application to embed Rubber Ducky inject.bin key scripts into custom firmware for execution on the drive. 7 | - `Injector` -- PC C# application to extract addresses/equates from firmware as well as embed patching code into the firmware. 8 | - `firmware` -- this is 8051 custom firmware written in C. 9 | - `patch` -- this is a collection of 8051 patch code written in C. 10 | 11 | Releases have the following items: 12 | - `patch` -- this is a collection of 8051 patch code written in C. 13 | - `tools` -- these are the compiled binaries of all the tools. 14 | - `CFW.bin` -- this is custom firmware set up to send an embedded HID payload. 15 | 16 | Take note that the firmware patches have only been tested against PS2251-03 firmware version _1.03.53_ (which is for an 8K eD3 NAND flash chip). They may work for others, but be careful. 17 | 18 | As long as you are using the correct firmware image for your controller version and NAND chip, there is no harm in downgrading to an earlier version (such as from 1.10.53). 19 | 20 | **WARNING: This is experimental software. Use on unsupported devices, or even on supported devices, may cause loss of data, or even permananent damage to devices. Use at your own risk.** 21 | 22 | ## Getting Started 23 | *See [Known Supported Devices](https://github.com/adamcaudill/Psychson/wiki/Known-Supported-Devices) for information on supported devices; use on an unsupported device may cause permanent damage to the device.* 24 | 25 | To get started, you'll need to obtain a burner image, which is the 8051 executable responsible for flashing firmware to the drive. 26 | 27 | See [Obtaining a Burner Image](https://github.com/adamcaudill/Psychson/wiki/Obtaining-a-Burner-Image) on the wiki for more information. 28 | 29 | ## Build Environment 30 | To patch or modify existing firmware, you must first set up a build environment. See [Setting Up the Environment](https://github.com/adamcaudill/Psychson/wiki/Setting-Up-the-Environment) on the wiki for more information. 31 | 32 | At a minimum, SDCC needs to be installed to `C:\Program Files\SDCC`. 33 | 34 | ## Dumping Firmware 35 | Run DriveCom, passing in the drive letter representing the drive you want to flash, the path of the burner image you obtained, and the destination path for the firmware image: 36 | 37 | tools\DriveCom.exe /drive=E /action=DumpFirmware /burner=BN03V104M.BIN /firmware=fw.bin 38 | 39 | where `E` is the drive letter, `BN03V104M.BIN` is the path to the burner image, and `fw.bin` is the resulting firmware dump. 40 | 41 | Currently, only 200KB firmware images can be dumped (which is what the [Patriot 8GB Supersonic Xpress](http://www.amazon.com/gp/product/B005EWB15W/) drive uses). 42 | 43 | ## Flashing Custom Firmware 44 | Run `DriveCom`, passing in the drive letter representing the drive you want to flash, the path of the burner image you obtained, and the path of the firmware image you want to flash: 45 | 46 | tools\DriveCom.exe /drive=E /action=SendFirmware /burner=BN03V104M.BIN /firmware=fw.bin 47 | 48 | where `E` is the drive letter, `BN03V104M.BIN` is the path to the burner image, and `fw.bin` is the path to the firmware image. 49 | 50 | ## Running Demo 1 (HID Payload) 51 | Create a key script in [Rubber Ducky format](https://github.com/hak5darren/USB-Rubber-Ducky/wiki/Payloads), then use [Duckencoder](https://code.google.com/p/ducky-decode/downloads/detail?name=DuckEncoder_2.6.3.zip&can=2&q=) to create an `inject.bin` version of it: 52 | 53 | java -jar duckencoder.java -i keys.txt -o inject.bin 54 | 55 | where `keys.txt` is the path to your key script. 56 | 57 | You may notice the delays are not quite the same between the Rubber Ducky and the drive -- you may need to adjust your scripts to compensate. 58 | 59 | (These tools are available from https://code.google.com/p/ducky-decode/.) 60 | 61 | Once you have an `inject.bin` file, embed it into the custom firmware with: 62 | 63 | copy CFW.bin hid.bin 64 | tools\EmbedPayload.exe inject.bin hid.bin 65 | 66 | where `inject.bin` is the path to your inject.bin file, and `hid.bin` is the path to the HID payload custom firmware. 67 | 68 | (Notice that the firmware image is copied, and the payload is embedded into the copy -- this is because the payload can only be embedded once, so the original `CFW.bin` must remain intact.) 69 | 70 | You can now flash the firmware to your drive with: 71 | 72 | tools\DriveCom.exe /drive=E /action=SendFirmware /burner=BN03V104M.BIN /firmware=hid.bin 73 | 74 | where `E` is the drive letter representing your drive, `BN03V104M.BIN` is the path to your burner image, and `hid.bin` is the path to the HID payload custom firmware. 75 | 76 | *Huge thanks to the [Hak5](http://hak5.org/) team for their work on the excellent [USB Rubber Ducky](https://hakshop.myshopify.com/collections/usb-rubber-ducky/products/usb-rubber-ducky-deluxe)!* 77 | 78 | ## Running Demo 2 (Hidden Partition Patch) 79 | First, determine the number of logical blocks (sectors) your drive has with the following command: 80 | 81 | tools\DriveCom.exe /drive=E /action=GetNumLBAs 82 | 83 | Go into the `patch` directory and modify `base.c` to disable all other patches, and enable the hidden partition patch: 84 | 85 | //#define FEATURE_CHANGE_PASSWORD 86 | 87 | #define FEATURE_EXPOSE_HIDDEN_PARTITION 88 | 89 | Then modify the `NUM_LBAS` define to the number of logical blocks on your drive: 90 | 91 | #define NUM_LBAS 0xE6C980UL //this needs to be even! (round down) 92 | 93 | Make sure you round down to an even number, and it couldn't hurt to subtract a few first, in case a few blocks go bad over time. (For example, if the number of LBAs was `0xE6C981`, you might reduce it to `0xE6C940`.) 94 | 95 | Place the firmware image you want to patch into the `patch` directory and name it `fw.bin`. 96 | 97 | Go to the `patch` directory and run `build.bat`. It will produce a file at `patch\bin\fw.bin` -- this is the modified firmware image. 98 | 99 | You can now flash this file to your drive. 100 | 101 | After flashing, Windows may be confused, as it now only sees half of the partition it once did -- it may ask you to format the first time you view either the public or hidden halves of the drive. This is normal. 102 | 103 | ## Running Demo 3 (Password Patch) 104 | Go into the `patch` directory and modify `base.c` to disable all other patches, and enable the password patch: 105 | 106 | #define FEATURE_CHANGE_PASSWORD 107 | 108 | //#define FEATURE_EXPOSE_HIDDEN_PARTITION 109 | 110 | Place the firmware image you want to patch into the `patch` directory and name it `fw.bin`. 111 | 112 | Go to the `patch` directory and run `build.bat`. It will produce a file at `patch\bin\fw.bin` -- this is the modified firmware image. 113 | 114 | You can now flash this file to your drive. 115 | 116 | ## Running No Boot Mode Patch 117 | Go into the `patch` directory and modify `base.c` to disable all other patches, and enable the no boot patch: 118 | 119 | //#define FEATURE_CHANGE_PASSWORD 120 | //#define FEATURE_EXPOSE_HIDDEN_PARTITION 121 | #define FEATURE_PREVENT_BOOT 122 | 123 | Place the firmware image you want to patch into the `patch` directory and name it `fw.bin`. 124 | 125 | Go to the `patch` directory and run `build.bat`. It will produce a file at `patch\bin\fw.bin` -- this is the modified firmware image. 126 | 127 | You can now flash this file to your drive. Once flashed to your device, it will no longer act on the command to jump to boot mode. To update the firmware again will require [shorting pins](https://github.com/adamcaudill/Psychson/blob/master/docs/PinsToShortUponPlugInForBootMode.jpg) on the controller. To make it impossible* to update, after flashing this patch coat the device with epoxy. 128 | 129 | * *Within reason; it may be possible to get to boot mode via an exploit or other non-standard method.* 130 | 131 | #### Converting to Mode 7 132 | You can run the `ModeConverterFF01.exe` application (see [Useful Links](https://github.com/adamcaudill/Psychson/wiki/Useful-Links)) to split the drive into public and secure partitions, or restore the original (mode 3) functionality. 133 | 134 | After converting to mode 7, you should be able to set, change, or disable the secure partition password with the `USB DISK Pro LOCK` utility. 135 | 136 | ## Building From Source 137 | Modify the C files in the `firmware` directory for custom firmware, or the `patch` directory for the firmware patches, then run the `build.bat` file in the appropriate directory. 138 | 139 | Once it has built successfully, use DriveCom to flash the resulting file (`bin\fw.bin`) to your drive: 140 | 141 | tools\DriveCom.exe /drive=E /action=SendFirmware /burner=BN03V104M.BIN /firmware=firmware\bin\fw.bin 142 | 143 | ...or... 144 | 145 | tools\DriveCom.exe /drive=E /action=SendFirmware /burner=BN03V104M.BIN /firmware=patch\bin\fw.bin 146 | 147 | ## Questions? Comments? Complaints? 148 | 149 | Unfortunately this isn't the most straightforward process at the moment, so if you have questions, open an [issue](https://github.com/adamcaudill/Psychson/issues) and we'll do our best to help (and update the readme/wiki). 150 | -------------------------------------------------------------------------------- /docs/PinsToShortUponPlugInForBootMode.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/docs/PinsToShortUponPlugInForBootMode.jpg -------------------------------------------------------------------------------- /firmware/build.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Set things up and create bin directory if necessary. 4 | SETLOCAL ENABLEDELAYEDEXPANSION 5 | SET BUILD_FILES= 6 | IF NOT EXIST bin\NUL MKDIR bin 7 | 8 | REM Build each file in the list. 9 | FOR %%A IN ( 10 | main 11 | timers 12 | usb 13 | control 14 | scsi 15 | ) DO ( 16 | ECHO *** Building %%A.c... 17 | sdcc --model-small -mmcs51 -pdefcpu -c -obin\%%A.rel %%A.c 18 | IF ERRORLEVEL 1 GOTO ERRORS 19 | SET "BUILD_FILES=!BUILD_FILES! bin\%%A.rel" 20 | ) 21 | 22 | REM Build Intel Hex and BIN versions of combined file. 23 | sdcc --xram-loc 0x6000 -o bin\output.hex %BUILD_FILES% 24 | IF ERRORLEVEL 1 GOTO ERRORS 25 | makebin -p bin\output.hex bin\output.bin 26 | 27 | REM Create firmware and burner images from templates. 28 | copy /y ..\templates\FWdummy.bin bin\fw.bin > NUL 29 | copy /y ..\templates\BNdummy.bin bin\bn.bin > NUL 30 | ..\tools\sfk partcopy bin\output.bin -fromto 0 -1 bin\fw.bin 512 -yes > NUL 31 | ..\tools\sfk partcopy bin\output.bin -fromto 0 -1 bin\bn.bin 512 -yes > NUL 32 | 33 | GOTO END 34 | 35 | :ERRORS 36 | ECHO *** There were errors^^! *** 37 | 38 | :END 39 | ECHO *** Done. 40 | 41 | ENDLOCAL 42 | -------------------------------------------------------------------------------- /firmware/control.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "usb.h" 3 | #include "timers.h" 4 | 5 | static const BYTE deviceDescriptor[] = { 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 6 | 0xFE, 0x13, 0x01, 0x52, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01 }; 7 | static const BYTE configDescriptor[] = { 0x09, 0x02, sizeof(configDescriptor) & 0xFF, sizeof(configDescriptor) >> 8, 0x02, 0x01, 0x00, 0x80, 0x4B, 8 | 0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, 0x00, 9 | 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, 10 | 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, 11 | 0x07, 0x05, 0x83, 0x03, 0x08, 0x00, 0x00, 12 | 0x09, 0x04, 0x01, 0x00, 0x02, 0x03, 0x01, 0x01, 0x00, 13 | 0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, 14 | sizeof(HIDreportDescriptor) & 0xFF, 15 | sizeof(HIDreportDescriptor) >> 8, 16 | 0x07, 0x05, 0x83, 0x03, 0x08, 0x00, 0x01, 17 | //This is a dummy endpoint to make the descriptor != 0x40, because the controller is stupid. 18 | 0x07, 0x05, 0x04, 0x03, 0x08, 0x00, 0x01 }; 19 | static const BYTE HIDreportDescriptor[] = { 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 20 | 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 21 | 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 22 | 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, 23 | 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, 24 | 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, 25 | 0x29, 0x65, 0x81, 0x00, 0xC0 }; 26 | static const BYTE deviceQualifierDescriptor[] = { 0x0A, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00 }; 27 | 28 | void EP0ACK() 29 | { 30 | EP0CS = bmEP0ACK; 31 | } 32 | 33 | static BYTE SetAddress() 34 | { 35 | BYTE ret = FALSE; 36 | 37 | if (wValue < 0x7F) 38 | { 39 | EP0ACK(); 40 | ret = TRUE; 41 | } 42 | 43 | return ret; 44 | } 45 | 46 | static BYTE GetDescriptor() 47 | { 48 | BYTE type = (wValue >> 8) & 0xFF; 49 | BYTE i, total; 50 | BYTE ret = FALSE; 51 | 52 | switch (type) 53 | { 54 | case 0x01: 55 | { 56 | for (i = 0; i < 0x12; i++) 57 | { 58 | EP0.fifo = deviceDescriptor[i]; 59 | } 60 | 61 | SendControlResponse(wLength < 0x12 ? wLength : 0x12); 62 | ret = TRUE; 63 | 64 | break; 65 | } 66 | case 0x02: 67 | { 68 | total = wLength < sizeof(configDescriptor) ? wLength : sizeof(configDescriptor); 69 | for (i = 0; i < total; i++) 70 | { 71 | EP0.fifo = configDescriptor[i]; 72 | } 73 | 74 | SendControlResponse(total); 75 | ret = TRUE; 76 | 77 | break; 78 | } 79 | case 0x06: 80 | { 81 | for (i = 0; i < sizeof(deviceQualifierDescriptor); i++) 82 | { 83 | EP0.fifo = deviceQualifierDescriptor[i]; 84 | } 85 | 86 | SendControlResponse(wLength < sizeof(deviceQualifierDescriptor) ? wLength : sizeof(deviceQualifierDescriptor)); 87 | ret = TRUE; 88 | 89 | break; 90 | } 91 | case 0x22: 92 | { 93 | for (i = 0; i < sizeof(HIDreportDescriptor); i++) 94 | { 95 | EP0.fifo = HIDreportDescriptor[i]; 96 | } 97 | 98 | SendControlResponse(wLength < sizeof(HIDreportDescriptor) ? wLength : sizeof(HIDreportDescriptor)); 99 | ret = TRUE; 100 | 101 | break; 102 | } 103 | default: 104 | { 105 | break; 106 | } 107 | } 108 | 109 | return ret; 110 | } 111 | 112 | static BYTE SetConfiguration() 113 | { 114 | BYTE ret = FALSE; 115 | 116 | if (wValue <= 1) 117 | { 118 | EP0ACK(); 119 | ret = TRUE; 120 | } 121 | 122 | return ret; 123 | } 124 | 125 | BYTE HandleStandardRequest() 126 | { 127 | switch(bRequest) 128 | { 129 | case 0x05: 130 | { 131 | return SetAddress(); 132 | } 133 | case 0x06: 134 | { 135 | return GetDescriptor(); 136 | } 137 | case 0x09: 138 | { 139 | return SetConfiguration(); 140 | } 141 | default: 142 | { 143 | return FALSE; 144 | } 145 | } 146 | } 147 | 148 | static BYTE GetMaxLUN() 149 | { 150 | EP0.fifo = 0x00; 151 | SendControlResponse(wLength < 0x01 ? wLength : 0x01); 152 | 153 | return TRUE; 154 | } 155 | 156 | BYTE HandleClassRequest() 157 | { 158 | switch(bRequest) 159 | { 160 | case 0x09: 161 | { 162 | EP0CS = 0x05; 163 | return TRUE; 164 | } 165 | case 0x0A: 166 | { 167 | EP0ACK(); 168 | return TRUE; 169 | } 170 | case 0xFE: 171 | { 172 | return GetMaxLUN(); 173 | } 174 | default: 175 | { 176 | return FALSE; 177 | } 178 | } 179 | } 180 | 181 | BYTE HandleVendorRequest() 182 | { 183 | return FALSE; 184 | } 185 | -------------------------------------------------------------------------------- /firmware/defs.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFS_H 2 | #define DEFS_H 3 | 4 | #define MSB(word) (BYTE)(((WORD)(word) >> 8) & 0xff) 5 | #define LSB(word) (BYTE)((WORD)(word) & 0xff) 6 | 7 | #define XVAL(addr) (*( __xdata volatile unsigned char *)(addr)) 8 | #define IVAL(addr) (*( __idata volatile unsigned char *)(addr)) 9 | 10 | typedef unsigned char BYTE; 11 | typedef unsigned short WORD; 12 | typedef unsigned long DWORD; 13 | #define TRUE 1 14 | #define FALSE 0 15 | 16 | #define BANK0_PA 0x008000UL 17 | #define BANK1_VA 0x4000U 18 | #define BANK1_PA 0x00C000UL 19 | #define BANK2_VA 0x6000U 20 | #define BANK2_PA 0x00E000UL 21 | 22 | #define usb_buffer_PA 0x008000UL 23 | #define usb_buffer_VA 0x0000U 24 | 25 | #define USB_VECT 0 26 | #define TMR0_VECT 1 27 | #define EP_VECT 2 28 | #define TMR1_VECT 3 29 | #define COM0_VECT 4 30 | 31 | #define bmAttach 0x80 32 | #define bmSpeed 7 33 | #define bmSuperSpeed 4 34 | #define bmHighSpeed 0 35 | #define bmFullSpeed 1 36 | #define bmSpeedChange 0x80 37 | #define bmEP2IRQ 2 38 | #define bmEP4IRQ 8 39 | #define bmEP0ACK 1 40 | #define bmEP0NAK 2 41 | #define bmEP0IN 4 42 | #define bmEP0STALL 8 43 | #define bmSUDAV 0x80 44 | #define bmSTALL 2 45 | 46 | #define bmNandReady 1 47 | 48 | #define bmNandDma0 0 49 | #define bmNandDma1 0x80 50 | #define bmNandDmaRead 0 51 | #define bmNandDmaWrite 0x40 52 | 53 | #define bmDmaCmd 7 54 | #define bmDmaCopy 2 55 | #define bmDmaFill 4 56 | #define bmDmaWidth8 0 57 | #define bmDmaWidth16 0x40 58 | #define bmDmaWidth32 0x80 59 | 60 | #define bmPRAM 1 61 | 62 | __sfr __at (0x80) P0 ; 63 | __sfr __at (0x90) P1 ; 64 | __sfr __at (0xA0) P2 ; 65 | __sfr __at (0xB0) P3 ; 66 | __sfr __at (0xD0) PSW ; 67 | __sfr __at (0xE0) ACC ; 68 | __sfr __at (0xF0) B ; 69 | __sfr __at (0x81) SP ; 70 | __sfr __at (0x82) DPL ; 71 | __sfr __at (0x83) DPH ; 72 | __sfr __at (0x87) PCON; 73 | __sfr __at (0x88) TCON; 74 | __sfr __at (0x89) TMOD; 75 | __sfr __at (0x8A) TL0 ; 76 | __sfr __at (0x8B) TL1 ; 77 | __sfr __at (0x8C) TH0 ; 78 | __sfr __at (0x8D) TH1 ; 79 | __sfr __at (0xA8) IE ; 80 | __sfr __at (0xB8) IP ; 81 | __sfr __at (0x98) SCON; 82 | __sfr __at (0x99) SBUF; 83 | 84 | /* BIT Register */ 85 | /* PSW */ 86 | __sbit __at (0xD7) CY ; 87 | __sbit __at (0xD6) AC ; 88 | __sbit __at (0xD5) F0 ; 89 | __sbit __at (0xD4) RS1 ; 90 | __sbit __at (0xD3) RS0 ; 91 | __sbit __at (0xD2) OV ; 92 | __sbit __at (0xD0) P ; 93 | 94 | /* TCON */ 95 | __sbit __at (0x8F) TF1 ; 96 | __sbit __at (0x8E) TR1 ; 97 | __sbit __at (0x8D) TF0 ; 98 | __sbit __at (0x8C) TR0 ; 99 | __sbit __at (0x8B) IE1 ; 100 | __sbit __at (0x8A) IT1 ; 101 | __sbit __at (0x89) IE0 ; 102 | __sbit __at (0x88) IT0 ; 103 | 104 | /* IE */ 105 | __sbit __at (0xAF) EA ; 106 | __sbit __at (0xAC) ES ; 107 | __sbit __at (0xAB) ET1 ; 108 | __sbit __at (0xAA) EX1 ; 109 | __sbit __at (0xA9) ET0 ; 110 | __sbit __at (0xA8) EX0 ; 111 | 112 | /* IP */ 113 | __sbit __at (0xBC) PS ; 114 | __sbit __at (0xBB) PT1 ; 115 | __sbit __at (0xBA) PX1 ; 116 | __sbit __at (0xB9) PT0 ; 117 | __sbit __at (0xB8) PX0 ; 118 | 119 | /* P3 */ 120 | __sbit __at (0xB7) RD ; 121 | __sbit __at (0xB6) WR ; 122 | __sbit __at (0xB5) T1 ; 123 | __sbit __at (0xB4) T0 ; 124 | __sbit __at (0xB3) INT1; 125 | __sbit __at (0xB2) INT0; 126 | __sbit __at (0xB1) TXD ; 127 | __sbit __at (0xB0) RXD ; 128 | 129 | /* SCON */ 130 | __sbit __at (0x9F) SM0 ; 131 | __sbit __at (0x9E) SM1 ; 132 | __sbit __at (0x9D) SM2 ; 133 | __sbit __at (0x9C) REN ; 134 | __sbit __at (0x9B) TB8 ; 135 | __sbit __at (0x9A) RB8 ; 136 | __sbit __at (0x99) TI ; 137 | __sbit __at (0x98) RI ; 138 | 139 | __xdata __at 0xF000 volatile BYTE REGBANK; 140 | __xdata __at 0xF008 volatile BYTE USBCTL; 141 | __xdata __at 0xF009 volatile BYTE USBSTAT; 142 | __xdata __at 0xF027 volatile BYTE USBIRQ; 143 | __xdata __at 0xF020 volatile BYTE EPIRQ; 144 | __xdata __at 0xF030 volatile BYTE EPIE; 145 | __xdata __at 0xF048 volatile BYTE EP0CS; 146 | __xdata __at 0xF0B8 volatile BYTE SETUPDAT[8]; 147 | 148 | typedef struct 149 | { 150 | BYTE r0, r1, r2, r3, r4; 151 | BYTE ptr_l, ptr_m, ptr_h; 152 | BYTE r8, r9; 153 | BYTE offset; 154 | BYTE rB; 155 | BYTE len_l, len_m, len_h; 156 | BYTE rF, r10, r11, r12; 157 | BYTE cs; 158 | BYTE r14, r15, r16, r17, r18, r19; 159 | BYTE fifo_count; 160 | BYTE r1B; 161 | BYTE fifo; 162 | } EPREGS; 163 | 164 | __xdata __at 0xF1C0 volatile EPREGS EP0; 165 | __xdata __at 0xF200 volatile EPREGS EP1; 166 | __xdata __at 0xF240 volatile EPREGS EP2; 167 | __xdata __at 0xF280 volatile EPREGS EP3; 168 | __xdata __at 0xF2C0 volatile EPREGS EP4; 169 | 170 | __xdata __at 0xF608 volatile BYTE NANDCSOUT; 171 | __xdata __at 0xF618 volatile BYTE NANDCSDIR; 172 | 173 | __xdata __at 0xF900 volatile BYTE DMASRCL; 174 | __xdata __at 0xF901 volatile BYTE DMASRCM; 175 | __xdata __at 0xF902 volatile BYTE DMASRCH; 176 | __xdata __at 0xF904 volatile BYTE DMADSTL; 177 | __xdata __at 0xF905 volatile BYTE DMADSTM; 178 | __xdata __at 0xF906 volatile BYTE DMADSTH; 179 | __xdata __at 0xF908 volatile BYTE DMASIZEL; 180 | __xdata __at 0xF909 volatile BYTE DMASIZEM; 181 | __xdata __at 0xF90A volatile BYTE DMASIZEH; 182 | __xdata __at 0xF90C volatile BYTE DMAFILL0; 183 | __xdata __at 0xF90D volatile BYTE DMAFILL1; 184 | __xdata __at 0xF90E volatile BYTE DMAFILL2; 185 | __xdata __at 0xF90F volatile BYTE DMAFILL3; 186 | __xdata __at 0xF930 volatile BYTE DMACMD; 187 | 188 | __xdata __at 0xFA14 volatile BYTE GPIO0DIR; 189 | __xdata __at 0xFA15 volatile BYTE GPIO0OUT; 190 | __xdata __at 0xFA38 volatile BYTE WARMSTATUS; 191 | 192 | __xdata __at 0xFA40 volatile BYTE BANK0PAL; 193 | __xdata __at 0xFA41 volatile BYTE BANK0PAH; 194 | __xdata __at 0xFA42 volatile BYTE BANK1VA; 195 | __xdata __at 0xFA43 volatile BYTE BANK1PAL; 196 | __xdata __at 0xFA44 volatile BYTE BANK1PAH; 197 | __xdata __at 0xFA45 volatile BYTE BANK2VA; 198 | __xdata __at 0xFA46 volatile BYTE BANK2PAL; 199 | __xdata __at 0xFA47 volatile BYTE BANK2PAH; 200 | __xdata __at 0xFA48 volatile BYTE PRAMCTL; //bit 0 set means run from PRAM 201 | 202 | #endif 203 | -------------------------------------------------------------------------------- /firmware/main.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "timers.h" 3 | #include "usb.h" 4 | 5 | extern void usb_isr(void) __interrupt USB_VECT; 6 | extern void ep_isr(void) __interrupt EP_VECT; 7 | extern void tmr0isr(void) __interrupt TMR0_VECT; 8 | extern void tmr1isr(void) __interrupt TMR1_VECT; 9 | 10 | #define KEY_DELAY 8192 11 | #define KEY_BUFFER_SIZE 0x2000 12 | static const BYTE keyData[KEY_BUFFER_SIZE] = { /*0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 13 | 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xC3, 14 | 0x15, 0x08, 0x00, 0xFF, 0x00, 0xF5, 0x11, 0x00, 0x12, 0x00, 0x17, 0x00, 0x08, 0x00, 0x13, 15 | 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0xFF, 0x00, 0xF5, 0x28, 0x00, 0x00, 0xFF, 0x00, 0xFF, 16 | 0x00, 0xF0, 0x0B, 0x02, 0x08, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x2C, 0x00, 0x1A, 17 | 0x02, 0x12, 0x00, 0x15, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, 0x02, 18 | 0x28, 0x00*/ 0x12, 0x34, 0x56, 0x78 }; 19 | int key_index = 0; 20 | volatile BYTE send_keys_enabled = 0; 21 | DWORD wait_counter = KEY_DELAY; 22 | DWORD wait_tick; 23 | 24 | void InitHardware() 25 | { 26 | //Set up RAM mapping just beyond our own code 27 | BANK0PAL = BANK0_PA>>9; 28 | BANK0PAH = BANK0_PA>>17; 29 | BANK1VA = BANK1_VA>>8; 30 | BANK1PAL = BANK1_PA>>9; 31 | BANK1PAH = BANK1_PA>>17; 32 | BANK2VA = BANK2_VA>>8; 33 | BANK2PAL = BANK2_PA>>9; 34 | BANK2PAH = BANK2_PA>>17; 35 | 36 | XVAL(0xF809) = 7; 37 | XVAL(0xF80A) = 0x1F; 38 | XVAL(0xF810) = 0x60; 39 | XVAL(0xF811) = 0; 40 | XVAL(0xF08F) = 0; 41 | 42 | XVAL(0xFA6F) = 0x1F; 43 | XVAL(0xFA60) = 2; 44 | XVAL(0xFA61) = 0; 45 | XVAL(0xFA64) = 0; 46 | XVAL(0xFA65) = 0; 47 | XVAL(0xFA66) = 0; 48 | XVAL(0xFA67) = 0; 49 | XVAL(0xFA62) = 0x0F; 50 | XVAL(0xFA6F) = 0x1F; 51 | 52 | GPIO0DIR &= 0xFD; 53 | GPIO0OUT |= 2; 54 | 55 | XVAL(0xFA21) = 7; 56 | XVAL(0xFA21) &= 0xFB; 57 | 58 | XVAL(0xFA68) &= 0xF7; 59 | XVAL(0xFA69) &= 0xF7; 60 | XVAL(0xFA6A) &= 0xF7; 61 | XVAL(0xFA6B) &= 0xF7; 62 | 63 | XVAL(0xFE00) = 0; 64 | XVAL(0xFE00) = 0x80; 65 | 66 | XVAL(0xFA50) = 0x20; 67 | 68 | XVAL(0xFE01) = 0; 69 | XVAL(0xFE02) = 0x45; 70 | 71 | TMOD = 0x11; 72 | TH0 = 0xF0; 73 | TL0 = 0x5F; 74 | TH1 = 0xF0; 75 | TL1 = 0x5F; 76 | IP = 1; 77 | TCON = 0x10; 78 | SCON = 0; 79 | IE = 0x80; 80 | } 81 | 82 | void DoUSBRelatedInit() 83 | { 84 | if (WARMSTATUS & 2) 85 | { 86 | return; 87 | } 88 | 89 | REGBANK = 5; 90 | XVAL(0xF210) = 0xFF; 91 | XVAL(0xF211) = 2; 92 | XVAL(0xF212) = 3; 93 | XVAL(0xF213) = 0x24; 94 | REGBANK = 0; 95 | XVAL(0xFA6B) = 0xFF; 96 | while((XVAL(0xF014) & 3)==0); 97 | } 98 | 99 | void SendKey(BYTE code, BYTE modifiers) 100 | { 101 | int i; 102 | 103 | EP3.cs = 0; 104 | while (EP3.cs & 0x40); 105 | 106 | EP3.fifo = modifiers; 107 | EP3.fifo = 0; 108 | EP3.fifo = code; 109 | for (i = 0; i < 5; i++) 110 | { 111 | EP3.fifo = 0; 112 | } 113 | 114 | EP3.len_l = 8; 115 | EP3.len_m = 0; 116 | EP3.len_h = 0; 117 | EP3.cs = 0x40; 118 | } 119 | 120 | void main() 121 | { 122 | InitHardware(); 123 | DoUSBRelatedInit(); 124 | InitUSB(); 125 | InitTicks(); 126 | InitLED(); 127 | LEDBlink(); 128 | 129 | while (1) 130 | { 131 | HandleUSBEvents(); 132 | 133 | if (wait_tick++ >= KEY_DELAY) 134 | { 135 | if (wait_counter < KEY_DELAY) 136 | { 137 | wait_counter++; 138 | } 139 | } 140 | 141 | if (send_keys_enabled && wait_counter >= KEY_DELAY) 142 | { 143 | if (keyData[key_index]) 144 | { 145 | //Send this key, with some padding before, since something's wonky with endpoint 3 146 | SendKey(0x00, 0x00); 147 | SendKey(0x00, 0x00); 148 | SendKey(0x00, 0x00); 149 | SendKey(0x00, 0x00); 150 | SendKey(keyData[key_index], keyData[key_index + 1]); 151 | SendKey(0x00, 0x00); 152 | } 153 | else 154 | { 155 | //Wait a while 156 | wait_counter = 0; 157 | wait_tick = 0; 158 | } 159 | 160 | //Move to next key 161 | key_index += 2; 162 | 163 | //Are we done? 164 | if (key_index >= sizeof(keyData)) 165 | { 166 | send_keys_enabled = 0; 167 | } 168 | } 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /firmware/scsi.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "string.h" 3 | #include "usb.h" 4 | 5 | #define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E 6 | #define TEST_UNIT_READY 0x00 7 | #define INQUIRY 0x12 8 | #define READ_FORMAT_CAPACITIES 0x23 9 | #define MODE_SENSE 0x1A 10 | #define REQUEST_SENSE 0x03 11 | 12 | #define VENDOR_BOOT 0xBF 13 | #define VENDOR_INFO 0x05 14 | #define VENDOR_CHIPID 0x56 15 | #define CUSTOM_XPEEK 0x06 16 | #define CUSTOM_XPOKE 0x07 17 | #define CUSTOM_IPEEK 0x08 18 | #define CUSTOM_IPOKE 0x09 19 | 20 | BYTE scsi_status; 21 | DWORD scsi_data_residue; 22 | DWORD scsi_transfer_size; 23 | BYTE scsi_tag[4]; 24 | BYTE scsi_dir_in; 25 | BYTE scsi_lun; 26 | BYTE scsi_cdb[16]; 27 | BYTE scsi_cdb_size; 28 | 29 | BYTE HandleCDB() 30 | { 31 | //Default to returning a bad status 32 | scsi_status = 1; 33 | 34 | switch(scsi_cdb[0]) 35 | { 36 | case PREVENT_ALLOW_MEDIUM_REMOVAL: 37 | { 38 | scsi_status = 0; 39 | return 1; 40 | } 41 | case TEST_UNIT_READY: 42 | { 43 | return 1; 44 | } 45 | case INQUIRY: 46 | { 47 | memset(usb_buffer, 0, 36); 48 | usb_buffer[1] = 0x80; //removable media 49 | usb_buffer[3] = 0x01; //because the UFI spec says so 50 | usb_buffer[4] = 0x1F; //additional length 51 | SendData1(36, 0); 52 | scsi_status = 0; 53 | return 1; 54 | } 55 | case READ_FORMAT_CAPACITIES: 56 | { 57 | memset(usb_buffer, 0, 12); 58 | usb_buffer[3] = 0x08; //capacity list length 59 | usb_buffer[6] = 0x10; //number of blocks (sectors) (dummy 2MB) 60 | usb_buffer[8] = 0x03; 61 | usb_buffer[10] = 0x02; //block length (512 bytes/sector) 62 | SendData1(12, 0); 63 | scsi_status = 0; 64 | return 1; 65 | } 66 | case MODE_SENSE: 67 | { 68 | memset(usb_buffer, 0, 8); 69 | usb_buffer[0] = 0x03; 70 | usb_buffer[2] = 0x80; 71 | SendData1(4, 0); 72 | scsi_status = 0; 73 | return 1; 74 | } 75 | case REQUEST_SENSE: 76 | { 77 | memset(usb_buffer, 0, 18); 78 | usb_buffer[0] = 0x70; 79 | usb_buffer[2] = 0x02; 80 | usb_buffer[7] = 10; 81 | usb_buffer[12] = 0x3A; 82 | SendData1(18, 0); 83 | scsi_status = 0; 84 | return 1; 85 | } 86 | //Vendor-specific requests 87 | case 0x06: 88 | case 0xC6: 89 | case 0xC7: 90 | { 91 | switch(scsi_cdb[1]) 92 | { 93 | case CUSTOM_XPEEK: 94 | { 95 | usb_buffer[0] = XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]); 96 | SendData1(1, 0); 97 | break; 98 | } 99 | case CUSTOM_XPOKE: 100 | { 101 | XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]) = scsi_cdb[4]; 102 | SendData1(1, 0); 103 | break; 104 | } 105 | case CUSTOM_IPEEK: 106 | { 107 | usb_buffer[0] = IVAL(scsi_cdb[2]); 108 | SendData1(1, 0); 109 | break; 110 | } 111 | case CUSTOM_IPOKE: 112 | { 113 | IVAL(scsi_cdb[2]) = scsi_cdb[3]; 114 | SendData1(1, 0); 115 | break; 116 | } 117 | case VENDOR_CHIPID: 118 | { 119 | int i; 120 | memset(usb_buffer, 0x00, 0x200); 121 | 122 | //Set raw command mode 123 | XVAL(0xF480) = 0x00; 124 | XVAL(0xF618) = 0xFF; 125 | 126 | //Select chip 0 127 | XVAL(0xF608) = 0xFE; 128 | 129 | //Reset it 130 | XVAL(0xF400) = 0xFF; 131 | while (!(XVAL(0xF41E) & 0x01)); 132 | 133 | //Send read chip ID command 134 | XVAL(0xF400) = 0x90; 135 | XVAL(0xF404) = 0x00; 136 | for (i = 0; i < 6; i++) 137 | { 138 | usb_buffer[i] = XVAL(0xF408); 139 | } 140 | 141 | SendData1(0x200, 0); 142 | scsi_status = 0; 143 | return 1; 144 | } 145 | case VENDOR_INFO: //get info 146 | { 147 | int i; 148 | 149 | memset(usb_buffer, 0x00, 0x210); 150 | usb_buffer[0x094] = 0x00; 151 | usb_buffer[0x095] = 0x99; 152 | usb_buffer[0x096] = 0x53; 153 | usb_buffer[0x17A] = 'V'; 154 | usb_buffer[0x17B] = 'R'; 155 | usb_buffer[0x17E] = 0x23; 156 | usb_buffer[0x17F] = 0x03; 157 | usb_buffer[0x200] = 'I'; 158 | usb_buffer[0x201] = 'F'; 159 | SendData1(0x210, 0); 160 | scsi_status = 0; 161 | return 1; 162 | } 163 | case VENDOR_BOOT: 164 | { 165 | //This transfers control to boot mode and will not return. 166 | XVAL(0xFA14) = 0x07; 167 | XVAL(0xF747) &= 0xEF; 168 | XVAL(0xFA15) = 0x06; 169 | XVAL(0xFA38) |= 0x01; 170 | XVAL(0xF08F) = 0x00; 171 | XVAL(0xFA68) &= 0xF7; 172 | XVAL(0xFA6A) &= 0xF7; 173 | XVAL(0xFA48) &= 0xFE; 174 | break; 175 | } 176 | default: 177 | { 178 | //Not handling it, then 179 | return 0; 180 | } 181 | } 182 | } 183 | default: 184 | { 185 | //Not handling it, then 186 | return 0; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /firmware/test.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | ..\tools\DriveCom /action=SendFirmware /drive=E /burner=..\BINs\BN03V104M.BIN /firmware=bin\fw.bin 3 | -------------------------------------------------------------------------------- /firmware/timers.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "timers.h" 3 | 4 | static BYTE tmr0count, led_ticks, led_timer, led_tick_threshold; 5 | static BYTE tmr1count; 6 | static WORD tmr1reload; 7 | 8 | void tmr1isr(void) __interrupt TMR1_VECT 9 | { 10 | TR1 = 0; 11 | TH1 = MSB(tmr1reload); 12 | TL1 = LSB(tmr1reload); 13 | tmr1count++; 14 | TR1 = 1; 15 | } 16 | 17 | void InitTicks() 18 | { 19 | if (XVAL(0xFA60) == 0x0F) 20 | { 21 | tmr1reload = 0xF63C; 22 | } 23 | else 24 | { 25 | tmr1reload = 0-(2500/(XVAL(0xFA60)+2)); 26 | } 27 | 28 | tmr1count = 0; 29 | TR1 = 0; 30 | ET1 = 1; 31 | TMOD = TMOD & 0x0F | 0x10; 32 | } 33 | 34 | BYTE GetTickCount(void) 35 | { 36 | return tmr1count; 37 | } 38 | 39 | void tmr0isr(void) __interrupt TMR0_VECT 40 | { 41 | //approx. 10 times per second 42 | TR0 = 0; 43 | TL0 = 0xE6; 44 | TH0 = 0x96; 45 | TR0 = 1; 46 | 47 | if ((GPIO0OUT & 2) == 0) //turned off 48 | { 49 | return; 50 | } 51 | 52 | tmr0count++; 53 | led_ticks++; 54 | if (led_ticks < led_tick_threshold) 55 | { 56 | return; 57 | } 58 | 59 | led_ticks = 0; 60 | if (led_timer >= 31) 61 | { 62 | GPIO0OUT = 1; 63 | led_timer = 0; 64 | return; 65 | } 66 | 67 | if (led_timer >= 10) 68 | { 69 | GPIO0OUT = ~GPIO0OUT; 70 | led_timer++; 71 | return; 72 | } 73 | 74 | if (led_timer == 0) 75 | { 76 | return; 77 | } 78 | 79 | if (GPIO0OUT & 1) 80 | { 81 | GPIO0OUT &= 0xFE; 82 | } 83 | else 84 | { 85 | GPIO0OUT |= 1; 86 | } 87 | } 88 | 89 | void SetLEDThreshold(int threshold) 90 | { 91 | led_tick_threshold = threshold; 92 | } 93 | 94 | void InitLED(void) 95 | { 96 | led_tick_threshold = 100; 97 | tmr0count = 0; 98 | GPIO0OUT = 3; 99 | led_ticks = 0; 100 | led_timer = 0; 101 | EA = 1; 102 | ET0 = 1; 103 | TR0 = 1; 104 | } 105 | 106 | void LEDBlink(void) 107 | { 108 | GPIO0OUT = 2; 109 | led_timer = 1; 110 | } 111 | 112 | void LEDOff(void) 113 | { 114 | GPIO0OUT = 3; 115 | led_timer = 0; 116 | } 117 | -------------------------------------------------------------------------------- /firmware/timers.h: -------------------------------------------------------------------------------- 1 | #ifndef _TIMERS_H_INCLUDED 2 | #define _TIMERS_H_INCLUDED 3 | 4 | void InitLED(void); 5 | void SetLEDThreshold(int threshold); 6 | void LEDBlink(void); 7 | void LEDOff(void); 8 | 9 | void InitTicks(); 10 | BYTE GetTickCount(void); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /firmware/usb.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "string.h" 3 | #include "timers.h" 4 | 5 | __xdata __at usb_buffer_VA volatile BYTE usb_buffer[1024]; 6 | 7 | BYTE bmRequestType; 8 | BYTE bRequest; 9 | WORD wValue; 10 | WORD wIndex; 11 | WORD wLength; 12 | 13 | static __xdata BYTE usb_irq; 14 | static __xdata BYTE UsbIntStsF080, UsbIntStsF082, UsbIntStsF086, UsbIntStsF087; 15 | 16 | BYTE usb_speed; 17 | __xdata volatile BYTE usb_received_data_ready, usb_have_csw_ready; 18 | 19 | extern BYTE scsi_status; 20 | extern DWORD scsi_data_residue; 21 | extern DWORD scsi_transfer_size; 22 | extern BYTE scsi_tag[4]; 23 | extern BYTE scsi_dir_in; 24 | extern BYTE scsi_cdb[16]; 25 | extern BYTE scsi_lun; 26 | extern BYTE scsi_cdb_size; 27 | extern BYTE HandleCDB(void); 28 | extern volatile BYTE send_keys_enabled; 29 | 30 | extern BYTE HandleStandardRequest(void); 31 | extern BYTE HandleClassRequest(void); 32 | extern BYTE HandleVendorRequest(void); 33 | 34 | void SetDMA(BYTE p5, BYTE p3, BYTE px) 35 | { 36 | XVAL(0xF80B) = 0; 37 | XVAL(0xF80C) = p5-1; 38 | 39 | switch(px) 40 | { 41 | case 0: 42 | { 43 | XVAL(0xF80D) = p3; 44 | XVAL(0xF80E) = p3; 45 | break; 46 | } 47 | case 1: 48 | { 49 | XVAL(0xF80D) = p3; 50 | break; 51 | } 52 | case 2: 53 | { 54 | XVAL(0xF80E) = p3; 55 | break; 56 | } 57 | default: 58 | { 59 | break; 60 | } 61 | } 62 | } 63 | 64 | void SendControlResponse(int size) 65 | { 66 | EP0.len_l = LSB(size); 67 | EP0.len_m = MSB(size); 68 | EP0.len_h = 0; 69 | EP0.cs = 0x40; 70 | while (EP0.cs & 0x40); 71 | EP0CS = 0x05; 72 | } 73 | 74 | void SendData0(WORD size, BYTE offset) 75 | { 76 | if (size > 0) 77 | { 78 | SetDMA(0x20, 0, 0); 79 | SetDMA(0x20, 0x80, 1); 80 | EP0.ptr_l = usb_buffer_PA>>8; 81 | EP0.ptr_m = usb_buffer_PA>>16; 82 | EP0.ptr_h = usb_buffer_PA>>24; 83 | EP0.offset = offset; 84 | EP0.len_l = LSB(size); 85 | EP0.len_m = MSB(size); 86 | EP0.len_h = 0; 87 | EP0.cs = 0x88; 88 | 89 | while(EP0.cs & 0x80); 90 | } 91 | } 92 | 93 | void SendData1(WORD size, BYTE offset) 94 | { 95 | if (size > 0) 96 | { 97 | SetDMA(0x20, 0, 0); 98 | SetDMA(0x20, 0x80, 1); 99 | EP1.ptr_l = usb_buffer_PA>>8; 100 | EP1.ptr_m = usb_buffer_PA>>16; 101 | EP1.ptr_h = usb_buffer_PA>>24; 102 | EP1.offset = offset; 103 | EP1.len_l = LSB(size); 104 | EP1.len_m = MSB(size); 105 | EP1.len_h = 0; 106 | EP1.cs = 0x88; 107 | 108 | while(EP1.cs & 0x80); 109 | } 110 | } 111 | 112 | static void SendCSW() 113 | { 114 | usb_buffer[0] = 'U'; 115 | usb_buffer[1] = 'S'; 116 | usb_buffer[2] = 'B'; 117 | usb_buffer[3] = 'S'; 118 | usb_buffer[4] = scsi_tag[0]; 119 | usb_buffer[5] = scsi_tag[1]; 120 | usb_buffer[6] = scsi_tag[2]; 121 | usb_buffer[7] = scsi_tag[3]; 122 | usb_buffer[8] = scsi_data_residue; 123 | usb_buffer[9] = scsi_data_residue>>8; 124 | usb_buffer[10] = scsi_data_residue>>16; 125 | usb_buffer[11] = scsi_data_residue>>24; 126 | usb_buffer[12] = scsi_status; 127 | 128 | SendData1(13, 0); 129 | usb_have_csw_ready = 0; 130 | scsi_data_residue = 0; 131 | } 132 | 133 | static void SendCSW2() 134 | { 135 | while(EP1.cs & bmSTALL); 136 | while((EP1.r17 & 0x80)==0) 137 | { 138 | if ((XVAL(0xF010) & 0x20)==0) 139 | { 140 | usb_have_csw_ready = 0; 141 | return; 142 | } 143 | } 144 | 145 | while(EP1.cs & 0x40); 146 | while(EP2.cs & 0x40); 147 | while(EP3.cs & 0x40); 148 | while(EP4.cs & 0x40); 149 | 150 | EP1.fifo = 'U'; 151 | EP1.fifo = 'S'; 152 | EP1.fifo = 'B'; 153 | EP1.fifo = 'S'; 154 | EP1.fifo = scsi_tag[0]; 155 | EP1.fifo = scsi_tag[1]; 156 | EP1.fifo = scsi_tag[2]; 157 | EP1.fifo = scsi_tag[3]; 158 | EP1.fifo = scsi_data_residue; 159 | EP1.fifo = scsi_data_residue>>8; 160 | EP1.fifo = scsi_data_residue>>16; 161 | EP1.fifo = scsi_data_residue>>24; 162 | EP1.fifo = scsi_status; 163 | EP1.len_l = 13; 164 | EP1.len_m = 0; 165 | EP1.len_h = 0; 166 | EP1.cs = 0x40; 167 | usb_have_csw_ready = 0; 168 | scsi_data_residue = 0; 169 | } 170 | 171 | void InitUSB(void) 172 | { 173 | BYTE b; 174 | 175 | usb_irq = 0; 176 | usb_received_data_ready = 0; 177 | usb_have_csw_ready = 0; 178 | usb_speed = 0; 179 | EP1.ptr_l = usb_buffer_PA>>8; 180 | EP1.ptr_m = usb_buffer_PA>>16; 181 | EP1.ptr_h = usb_buffer_PA>>24; 182 | EP1.r8 = 0x10; 183 | EP1.offset = 0; 184 | EP2.ptr_l = usb_buffer_PA>>8; 185 | EP2.ptr_m = usb_buffer_PA>>16; 186 | EP2.ptr_h = usb_buffer_PA>>24; 187 | EP2.r8 = 0x10; 188 | EP2.offset = 0; 189 | 190 | if (WARMSTATUS & 2) //USB warm start 191 | { 192 | if ((USBSTAT & bmSpeed) == bmSuperSpeed) 193 | { 194 | usb_speed = bmSuperSpeed; 195 | } 196 | else if ((USBSTAT & bmSpeed) == bmHighSpeed) 197 | { 198 | usb_speed = bmHighSpeed; 199 | } 200 | else if ((USBSTAT & bmSpeed) == bmFullSpeed) 201 | { 202 | usb_speed = bmFullSpeed; 203 | } 204 | else 205 | { 206 | usb_speed = 0; 207 | } 208 | 209 | EX1 = 1; 210 | EX0 = 1; 211 | EPIE = bmEP2IRQ | bmEP4IRQ; 212 | scsi_data_residue = 0; 213 | scsi_status = 0; 214 | SendCSW(); 215 | } 216 | else 217 | { 218 | //USB cold start 219 | REGBANK = 6; 220 | XVAL(0xF240) = 2; 221 | XVAL(0xF28C) = 0x36; 222 | XVAL(0xF28D) = 0xD0; 223 | XVAL(0xF28E) = 0x98; 224 | REGBANK = 0; 225 | EPIE = bmEP2IRQ | bmEP4IRQ; 226 | USBCTL = bmAttach | bmSuperSpeed; 227 | 228 | XVAL(0xFA38) |= 2; 229 | 230 | EX1 = 1; 231 | EX0 = 1; 232 | for (b = 0; b < 250; b++); 233 | } 234 | } 235 | 236 | void usb_isr(void) __interrupt USB_VECT 237 | { 238 | usb_irq = USBIRQ; 239 | 240 | if (usb_irq & 0x20) 241 | { 242 | USBIRQ = 0x20; 243 | } 244 | 245 | if (usb_irq & 0x10) 246 | { 247 | USBIRQ = 0x10; 248 | } 249 | 250 | if (usb_irq & bmSpeedChange) 251 | { 252 | USBIRQ = bmSpeedChange; 253 | if ((USBSTAT & bmSpeed) == bmSuperSpeed) 254 | { 255 | usb_speed = bmSuperSpeed; 256 | } 257 | else if ((USBSTAT & bmSpeed) == bmHighSpeed) 258 | { 259 | usb_speed = bmHighSpeed; 260 | } 261 | else if ((USBSTAT & bmSpeed) == bmFullSpeed) 262 | { 263 | usb_speed = bmFullSpeed; 264 | } 265 | else 266 | { 267 | usb_speed = 0; 268 | } 269 | } 270 | 271 | if (usb_irq & 0x40) 272 | { 273 | USBIRQ = 0x40; 274 | } 275 | 276 | UsbIntStsF087 = XVAL(0xF087); 277 | UsbIntStsF086 = XVAL(0xF086); 278 | UsbIntStsF082 = XVAL(0xF082); 279 | UsbIntStsF080 = XVAL(0xF080); 280 | 281 | if (UsbIntStsF082 & 0x80) 282 | { 283 | XVAL(0xF082) = 0x80; 284 | } 285 | 286 | if (UsbIntStsF082 & 0x40) 287 | { 288 | XVAL(0xF082) = 0x40; 289 | } 290 | 291 | if (UsbIntStsF080 & 1) 292 | { 293 | XVAL(0xF080) = 1; 294 | if (EP0CS & bmSUDAV) 295 | { 296 | bmRequestType = SETUPDAT[0]; 297 | bRequest = SETUPDAT[1]; 298 | wValue = SETUPDAT[2] | (SETUPDAT[3] << 8); 299 | wIndex = SETUPDAT[4] | (SETUPDAT[5] << 8); 300 | wLength = SETUPDAT[6] | (SETUPDAT[7] << 8); 301 | } 302 | } 303 | 304 | if (XVAL(0xF082) & 0x20) 305 | { 306 | XVAL(0xF082) = 0x20; 307 | } 308 | 309 | if (XVAL(0xF081) & 0x10) 310 | { 311 | XVAL(0xF081) = 0x10; 312 | } 313 | 314 | if (XVAL(0xF081) & 0x20) 315 | { 316 | XVAL(0xF081) = 0x20; 317 | } 318 | 319 | if (UsbIntStsF080 | UsbIntStsF082 | UsbIntStsF086 | UsbIntStsF087 | usb_irq) 320 | { 321 | EX0 = 0; 322 | } 323 | } 324 | 325 | void ep_isr(void) __interrupt EP_VECT 326 | { 327 | BYTE interrupts = (EPIRQ & (bmEP2IRQ | bmEP4IRQ)); 328 | if (interrupts & bmEP2IRQ) 329 | { 330 | EPIE &= ~bmEP2IRQ; //disable this 331 | EPIRQ = bmEP2IRQ; //acknowledge it 332 | usb_received_data_ready |= bmEP2IRQ; 333 | } 334 | 335 | if (interrupts & bmEP4IRQ) 336 | { 337 | EPIE &= ~bmEP4IRQ; //disable this 338 | EPIRQ = bmEP4IRQ; //acknowledge it 339 | usb_received_data_ready |= bmEP4IRQ; 340 | } 341 | } 342 | 343 | static void ResetEPs() 344 | { 345 | EPIE = bmEP2IRQ | bmEP4IRQ; 346 | EP1.cs = 0; 347 | EP2.cs = 0; 348 | EP3.cs = 0; 349 | EP4.cs = 0; 350 | } 351 | 352 | static void HandleControlRequest(void) 353 | { 354 | BYTE res; 355 | switch(bmRequestType & 0x60) 356 | { 357 | case 0: 358 | res = HandleStandardRequest(); 359 | break; 360 | case 0x20: 361 | res = HandleClassRequest(); 362 | break; 363 | case 0x40: 364 | res = HandleVendorRequest(); 365 | break; 366 | default: 367 | res = FALSE; 368 | } 369 | 370 | if (!res) 371 | { 372 | EP0CS = wLength ? bmEP0STALL : bmEP0NAK; 373 | } 374 | } 375 | 376 | void HandleUSBEvents(void) 377 | { 378 | if (UsbIntStsF080 | UsbIntStsF082 | UsbIntStsF086 | UsbIntStsF087 | usb_irq) 379 | { 380 | if (usb_irq) 381 | { 382 | if (usb_irq & 0x40) 383 | { 384 | USBCTL &= ~bmAttach; 385 | ResetEPs(); 386 | XVAL(0xFE88) = 0; 387 | XVAL(0xFE82) = 0x10; 388 | while(XVAL(0xFE88)!=2); 389 | USBCTL = bmAttach; 390 | } 391 | 392 | if (usb_irq & bmSpeedChange) 393 | { 394 | ResetEPs(); 395 | } 396 | 397 | usb_irq = 0; 398 | } 399 | else 400 | { 401 | if (UsbIntStsF082 & 0xC0) 402 | { 403 | ResetEPs(); 404 | XVAL(0xF092) = 0; 405 | XVAL(0xF096) = 0; 406 | if (UsbIntStsF082 & 0x40) 407 | { 408 | XVAL(0xF07A) = 1; 409 | } 410 | } 411 | else 412 | { 413 | if (UsbIntStsF080 & 1) 414 | { 415 | HandleControlRequest(); 416 | } 417 | } 418 | 419 | UsbIntStsF080 = 0; 420 | UsbIntStsF082 = 0; 421 | UsbIntStsF086 = 0; 422 | UsbIntStsF087 = 0; 423 | } 424 | 425 | EX0 = 1; 426 | } 427 | 428 | //WHY DOESN'T THIS INTERRUPT FIRE?! 429 | if (1)//usb_received_data_ready) 430 | { 431 | if (1)//usb_received_data_ready & bmEP4IRQ) 432 | { 433 | if (EP4.fifo_count > 0) 434 | { 435 | EP4.cs = 0x40; 436 | 437 | send_keys_enabled = 1; 438 | usb_received_data_ready &= ~bmEP4IRQ; 439 | EPIE |= bmEP4IRQ; 440 | } 441 | } 442 | 443 | if (usb_received_data_ready & bmEP2IRQ) 444 | { 445 | if (EP2.fifo_count == 31) //CBW size 446 | { 447 | BYTE a, b, c, d; 448 | 449 | scsi_data_residue = 0; 450 | /*while(EP1.cs & 0x40); 451 | while(EP2.cs & 0x40); 452 | while(EP3.cs & 0x40); 453 | while(EP4.cs & 0x40);*/ 454 | 455 | a = EP2.fifo; 456 | b = EP2.fifo; 457 | c = EP2.fifo; 458 | d = EP2.fifo; 459 | if ((a=='U') && (b=='S') && (c=='B') && (d=='C')) 460 | { 461 | scsi_tag[0] = EP2.fifo; 462 | scsi_tag[1] = EP2.fifo; 463 | scsi_tag[2] = EP2.fifo; 464 | scsi_tag[3] = EP2.fifo; 465 | scsi_transfer_size = EP2.fifo; 466 | scsi_transfer_size |= ((DWORD)EP2.fifo)<<8; 467 | scsi_transfer_size |= ((DWORD)EP2.fifo)<<16; 468 | scsi_transfer_size |= ((DWORD)EP2.fifo)<<24; 469 | scsi_dir_in = EP2.fifo & 0x80; 470 | scsi_lun = EP2.fifo; 471 | scsi_cdb_size = EP2.fifo; 472 | for(a = 0; a < 16; a++) 473 | { 474 | scsi_cdb[a] = EP2.fifo; 475 | } 476 | 477 | EP2.cs = 0x40; 478 | if (!HandleCDB()) 479 | { 480 | scsi_status = 1; 481 | if (scsi_transfer_size == 0) 482 | { 483 | EP1.cs = bmSTALL; 484 | } 485 | else if (scsi_dir_in) 486 | { 487 | EP1.cs = bmSTALL; 488 | } 489 | else 490 | { 491 | EP2.cs = bmSTALL; 492 | } 493 | } 494 | 495 | usb_have_csw_ready = 1; 496 | } 497 | else 498 | { 499 | EP2.cs = 0x40; 500 | EP2.cs = 4; 501 | } 502 | } 503 | else 504 | { 505 | EP2.cs = 0x40; 506 | EP2.cs = 4; 507 | } 508 | 509 | usb_received_data_ready &= ~bmEP2IRQ; 510 | EPIE |= bmEP2IRQ; 511 | } 512 | } 513 | 514 | if (usb_have_csw_ready) 515 | { 516 | SendCSW2(); 517 | } 518 | } 519 | -------------------------------------------------------------------------------- /firmware/usb.h: -------------------------------------------------------------------------------- 1 | #ifndef _USB_H_INCLUDED 2 | #define _USB_H_INCLUDED 3 | 4 | void InitUSB(void); 5 | void HandleUSBEvents(void); 6 | void SendControlResponse(int size); 7 | void SendData0(WORD size, BYTE offset); 8 | void SendData1(WORD size, BYTE offset); 9 | void SetDMA(BYTE p5, BYTE p3, BYTE px); 10 | 11 | extern BYTE bmRequestType; 12 | extern BYTE bRequest; 13 | extern WORD wValue; 14 | extern WORD wIndex; 15 | extern WORD wLength; 16 | 17 | extern BYTE usb_speed; 18 | extern __xdata __at usb_buffer_VA volatile BYTE usb_buffer[1024]; 19 | extern __xdata volatile BYTE usb_received_data_ready; 20 | extern __xdata volatile BYTE usb_have_csw_ready; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /patch/base.c: -------------------------------------------------------------------------------- 1 | #include "defs.h" 2 | #include "equates.h" 3 | 4 | #define FEATURE_CHANGE_PASSWORD 5 | //#define FEATURE_EXPOSE_HIDDEN_PARTITION 6 | //#define FEATURE_PREVENT_BOOT 7 | 8 | #define NUM_LBAS 0xE6EA40UL //this needs to be even! (round down) 9 | 10 | //SCSI command codes 11 | #define SCSI_06 0x06 12 | #define SCSI_06_XPEEK 0x06 13 | #define SCSI_06_XPOKE 0x07 14 | #define SCSI_06_IPEEK 0x08 15 | #define SCSI_06_IPOKE 0x09 16 | #define SCSI_06_BOOT 0xBF 17 | #define SCSI_START_STOP_UNIT 0x1B 18 | #define SCSI_READ_FORMAT_CAPACITIES 0x23 19 | #define SCSI_READ_CAPACITY 0x25 20 | #define SCSI_READ_SECTOR 0x28 21 | #define SCSI_WRITE_SECTOR 0x2A 22 | 23 | void memset(BYTE* s, BYTE c, int size) 24 | { 25 | int i; 26 | for (i = 0; i < size; i++) 27 | { 28 | *s = c; 29 | s++; 30 | } 31 | } 32 | 33 | void SendData(int size) 34 | { 35 | int i; 36 | 37 | while(EP1.cs & bmSTALL); 38 | while((EP1.r17 & 0x80)==0) 39 | { 40 | if ((XVAL(0xF010) & 0x20)==0) 41 | { 42 | return; 43 | } 44 | } 45 | 46 | while(EP1.cs & 0x40); 47 | while(EP2.cs & 0x40); 48 | while(EP3.cs & 0x40); 49 | while(EP4.cs & 0x40); 50 | 51 | for (i = 0; i < size; i++) 52 | { 53 | EP1.fifo = EPBUF[i]; 54 | } 55 | 56 | EP1.len_l = size & 0xFF; 57 | EP1.len_m = (size >> 8) & 0xFF; 58 | EP1.len_h = 0; 59 | EP1.cs = 0x40; 60 | } 61 | 62 | void SendCSW(void) 63 | { 64 | memset(EPBUF, 0, 13); 65 | EPBUF[0] = 'U'; 66 | EPBUF[1] = 'S'; 67 | EPBUF[2] = 'B'; 68 | EPBUF[3] = 'S'; 69 | EPBUF[4] = scsi_tag[3]; 70 | EPBUF[5] = scsi_tag[2]; 71 | EPBUF[6] = scsi_tag[1]; 72 | EPBUF[7] = scsi_tag[0]; 73 | SendData(13); 74 | } 75 | 76 | //Disconnects and then re-enumerates. 77 | void RecycleUSBConnection(void) 78 | { 79 | USBCTL &= ~bmAttach; 80 | EPIE = bmEP2IRQ; 81 | EP1.cs = 0; 82 | EP2.cs = 0; 83 | XVAL(0xFE88) = 0; 84 | XVAL(0xFE82) = 0x10; 85 | while (XVAL(0xFE88) != 2); 86 | USBCTL = bmAttach; 87 | } 88 | 89 | #ifdef FEATURE_EXPOSE_HIDDEN_PARTITION 90 | 91 | //HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status, 92 | // since we don't yet know what RAM is safe to use. 93 | BOOL IsHiddenAreaVisible(void) 94 | { 95 | return WARMSTATUS & 0x80; 96 | } 97 | 98 | //HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status, 99 | // since we don't yet know what RAM is safe to use. 100 | void SetHiddenAreaVisibility(BOOL visible) 101 | { 102 | if (visible) 103 | { 104 | WARMSTATUS |= 0x80; 105 | } 106 | else 107 | { 108 | WARMSTATUS &= 0x7F; 109 | } 110 | } 111 | 112 | void WaitTenSeconds(void) 113 | { 114 | WORD i, j; 115 | 116 | for (i = 0; i < 65535; i++) 117 | { 118 | for (j = 0; j < 1000; j++) 119 | { 120 | //Do nothing 121 | } 122 | } 123 | } 124 | 125 | #endif 126 | 127 | /* 128 | void HandleControlRequest(void) 129 | { 130 | if (bmRequestType & 0x20) 131 | { 132 | //Handle class request 133 | } 134 | else if (bmRequestType & 0x40) 135 | { 136 | //Handle vendor request 137 | } 138 | else 139 | { 140 | //Handle standard request 141 | } 142 | } 143 | */ 144 | 145 | /* 146 | void EndpointInterrupt(void) 147 | { 148 | __asm 149 | push ACC 150 | push DPH 151 | push DPL 152 | //If no interrupts fired, get out 153 | mov DPTR, #EPIRQ 154 | movx A, @DPTR 155 | jz 000001$ 156 | //Let the firmware know these events happened, so it can handle them 157 | mov B, A 158 | mov DPTR, #FW_EPIRQ 159 | movx A, @DPTR 160 | orl A, B 161 | movx @DPTR, A 162 | //Disable those interrupts so they don't fire again until we're done with them 163 | mov A, #0xFF 164 | xrl A, B 165 | mov DPTR, #EPIE 166 | movx @DPTR, A 167 | //Acknowledge the interrupts 168 | mov A, B 169 | mov DPTR, #EPIRQ 170 | movx @DPTR, A 171 | 000001$:pop DPL 172 | pop DPH 173 | pop ACC 174 | reti 175 | __endasm; 176 | } 177 | 178 | void HandleEndpointInterrupt(void) 179 | { 180 | //Handle incoming endpoint data 181 | } 182 | */ 183 | 184 | #if defined(FEATURE_EXPOSE_HIDDEN_PARTITION) || defined(FEATURE_PREVENT_BOOT) 185 | 186 | void HandleCDB(void) 187 | { 188 | unsigned long lba; 189 | 190 | switch(scsi_cdb[0]) 191 | { 192 | case SCSI_06: 193 | { 194 | switch (scsi_cdb[1]) 195 | { 196 | case SCSI_06_XPEEK: 197 | { 198 | EPBUF[0] = XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]); 199 | SendData(1); 200 | break; 201 | } 202 | case SCSI_06_XPOKE: 203 | { 204 | XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]) = scsi_cdb[4]; 205 | SendData(1); 206 | break; 207 | } 208 | case SCSI_06_IPEEK: 209 | { 210 | EPBUF[0] = IVAL(scsi_cdb[2]); 211 | SendData(1); 212 | break; 213 | } 214 | case SCSI_06_IPOKE: 215 | { 216 | IVAL(scsi_cdb[2]) = scsi_cdb[3]; 217 | SendData(1); 218 | break; 219 | } 220 | #ifdef FEATURE_PREVENT_BOOT 221 | case SCSI_06_BOOT: 222 | { 223 | break; 224 | } 225 | #endif 226 | default: 227 | { 228 | __asm 229 | ljmp #DEFAULT_CDB_HANDLER 230 | __endasm; 231 | } 232 | } 233 | break; 234 | } 235 | case SCSI_READ_SECTOR: //TODO: we should handle the other READ(X) commands as well 236 | { 237 | #ifdef FEATURE_EXPOSE_HIDDEN_PARTITION 238 | //Get the passed-in LBA 239 | lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000; 240 | lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000; 241 | lba |= (scsi_cdb[4] << 8) & 0xFF00; 242 | lba |= scsi_cdb[5]; 243 | 244 | //Shift it if necessary 245 | if (IsHiddenAreaVisible()) 246 | { 247 | lba += NUM_LBAS / 2; 248 | } 249 | 250 | //Save it 251 | scsi_cdb[2] = (lba >> 24) & 0xFF; 252 | scsi_cdb[3] = (lba >> 16) & 0xFF; 253 | scsi_cdb[4] = (lba >> 8) & 0xFF; 254 | scsi_cdb[5] = lba & 0xFF; 255 | #endif 256 | //Let the firmware do its thing 257 | __asm 258 | ljmp #DEFAULT_READ_SECTOR_HANDLER 259 | __endasm; 260 | } 261 | #ifdef FEATURE_EXPOSE_HIDDEN_PARTITION 262 | case SCSI_START_STOP_UNIT: 263 | { 264 | //Are we being stopped? 265 | if (scsi_cdb[4] == 0x02) 266 | { 267 | //Yes, set the other section as the visible one 268 | SetHiddenAreaVisibility(!IsHiddenAreaVisible()); 269 | 270 | //Send the CSW 271 | SendCSW(); 272 | 273 | //Wait and re-enumerate 274 | WaitTenSeconds(); 275 | RecycleUSBConnection(); 276 | } 277 | else 278 | { 279 | //No, let things continue normally 280 | __asm 281 | ljmp #DEFAULT_CDB_HANDLER 282 | __endasm; 283 | } 284 | break; 285 | } 286 | case SCSI_READ_FORMAT_CAPACITIES: 287 | { 288 | lba = NUM_LBAS / 2; 289 | 290 | memset(EPBUF, 0, 12); 291 | EPBUF[3] = 0x08; //capacity list length 292 | EPBUF[4] = lba >> 24; 293 | EPBUF[5] = lba >> 16; 294 | EPBUF[6] = lba >> 8; 295 | EPBUF[7] = lba & 0xFF; 296 | EPBUF[8] = 0x02; //descriptor code (formatted media) 297 | EPBUF[10] = 0x02; //block length (512 bytes/sector) 298 | SendData(12); 299 | break; 300 | } 301 | case SCSI_READ_CAPACITY: 302 | { 303 | lba = (NUM_LBAS / 2) - 1; 304 | 305 | memset(EPBUF, 0, 8); 306 | EPBUF[0] = lba >> 24; 307 | EPBUF[1] = lba >> 16; 308 | EPBUF[2] = lba >> 8; 309 | EPBUF[3] = lba & 0xFF; 310 | EPBUF[6] = 0x02; //block length (512 bytes/sector) 311 | SendData(8); 312 | break; 313 | } 314 | case SCSI_WRITE_SECTOR: //TODO: we should handle the other WRITE(x) commands as well 315 | { 316 | //Get the passed-in LBA 317 | lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000; 318 | lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000; 319 | lba |= (scsi_cdb[4] << 8) & 0xFF00; 320 | lba |= scsi_cdb[5]; 321 | 322 | //Shift it if necessary 323 | if (IsHiddenAreaVisible()) 324 | { 325 | lba += NUM_LBAS / 2; 326 | } 327 | 328 | //Save it 329 | scsi_cdb[2] = (lba >> 24) & 0xFF; 330 | scsi_cdb[3] = (lba >> 16) & 0xFF; 331 | scsi_cdb[4] = (lba >> 8) & 0xFF; 332 | scsi_cdb[5] = lba & 0xFF; 333 | 334 | //Let the firmware do its thing 335 | __asm 336 | ljmp #DEFAULT_CDB_HANDLER 337 | __endasm; 338 | } 339 | #endif 340 | default: 341 | __asm 342 | ljmp #DEFAULT_CDB_HANDLER 343 | __endasm; 344 | } 345 | } 346 | 347 | #endif 348 | 349 | //Called in the firmware's infinite loop. 350 | /* 351 | void LoopDo(void) 352 | { 353 | } 354 | */ 355 | 356 | #ifdef FEATURE_CHANGE_PASSWORD 357 | 358 | void SetPassword(BYTE* address) 359 | { 360 | int i; 361 | for (i = 0; i < 16; i++) 362 | { 363 | *(address + i) = 'A'; 364 | } 365 | } 366 | 367 | void PasswordReceived() 368 | { 369 | if (EPBUF[0]) 370 | { 371 | SetPassword(EPBUF); 372 | 373 | } 374 | 375 | if (EPBUF[0x10]) 376 | { 377 | SetPassword(EPBUF + 0x10); 378 | } 379 | } 380 | 381 | #endif 382 | -------------------------------------------------------------------------------- /patch/build.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Set things up and create bin directory if necessary. 4 | SETLOCAL ENABLEDELAYEDEXPANSION 5 | SET BUILD_FILES= 6 | IF NOT EXIST bin\NUL MKDIR bin 7 | 8 | REM Generate .h C file for compilation. 9 | ECHO *** Generating C .h file... 10 | ..\tools\Injector.exe /action=GenerateHFile /firmware=fw.bin /output=equates.h 11 | IF ERRORLEVEL 1 GOTO ERRORS 12 | 13 | REM Build each file in the list. 14 | REM NOTE: This needs to change if more code files or sections are added. 15 | FOR %%A IN ( 16 | base 17 | ) DO ( 18 | ECHO *** Building %%A.c... 19 | sdcc --model-small -mmcs51 -pdefcpu -c -obin\%%A.rel %%A.c 20 | IF ERRORLEVEL 1 GOTO ERRORS 21 | SET "BUILD_FILES=!BUILD_FILES! bin\%%A.rel" 22 | ) 23 | 24 | REM Retrieve free space for each section in the image. 25 | ECHO *** Retrieving free space in image... 26 | ..\tools\Injector.exe /action=FindFreeBlock /firmware=fw.bin /section=Base /output=bin\free.txt 27 | SET BASE_FREE_ADDR= 28 | FOR /F "delims=" %%i IN (bin\free.txt) DO SET BASE_FREE_ADDR=!BASE_FREE_ADDR! %%i 29 | DEL bin\free.txt 30 | 31 | REM Build Intel Hex and BIN versions of combined file. 32 | ECHO *** Linking... 33 | sdcc --model-small --code-loc %BASE_FREE_ADDR% --xram-size 0x400 --xram-loc 0x7C00 -o bin\output.hex %BUILD_FILES% 34 | ..\tools\hex2bin bin\output.hex 35 | 36 | REM Build patched image from assembled image. 37 | REM NOTE: This needs to change if more code files or sections are added. 38 | ECHO *** Injecting... 39 | ..\tools\Injector.exe /action=ApplyPatches /firmware=fw.bin /basecode=bin\output.bin /baserst=bin\base.rst /output=bin\fw.bin 40 | IF ERRORLEVEL 1 GOTO ERRORS 41 | 42 | GOTO END 43 | 44 | :ERRORS 45 | ECHO *** There were errors^^! *** 46 | 47 | :END 48 | ECHO *** Done. 49 | 50 | ENDLOCAL 51 | -------------------------------------------------------------------------------- /patch/defs.h: -------------------------------------------------------------------------------- 1 | #ifndef DEFS_H 2 | #define DEFS_H 3 | 4 | #define MSB(word) (BYTE)(((WORD)(word) >> 8) & 0xff) 5 | #define LSB(word) (BYTE)((WORD)(word) & 0xff) 6 | 7 | #define XVAL(addr) (*( __xdata volatile unsigned char *)(addr)) 8 | #define IVAL(addr) (*( __idata volatile unsigned char *)(addr)) 9 | 10 | typedef unsigned char BYTE; 11 | typedef unsigned short WORD; 12 | typedef unsigned long DWORD; 13 | typedef __bit BOOL; 14 | typedef __bit bit; 15 | #define TRUE 1 16 | #define FALSE 0 17 | 18 | #define USB_VECT 0 19 | #define TMR0_VECT 1 20 | #define EP_VECT 2 21 | #define TMR1_VECT 3 22 | #define COM0_VECT 4 23 | 24 | #define bmAttach 0x80 25 | #define bmSpeed 7 26 | #define bmSuperSpeed 4 27 | #define bmHighSpeed 0 28 | #define bmFullSpeed 1 29 | #define bmSpeedChange 0x80 30 | #define bmEP2IRQ 2 31 | #define bmEP0ACK 1 32 | #define bmEP0NAK 2 33 | #define bmEP0IN 4 34 | #define bmEP0STALL 8 35 | #define bmSUDAV 0x80 36 | #define bmSTALL 2 37 | 38 | #define bmNandReady 1 39 | 40 | #define bmNandDma0 0 41 | #define bmNandDma1 0x80 42 | #define bmNandDmaRead 0 43 | #define bmNandDmaWrite 0x40 44 | 45 | #define bmDmaCmd 7 46 | #define bmDmaCopy 2 47 | #define bmDmaFill 4 48 | #define bmDmaWidth8 0 49 | #define bmDmaWidth16 0x40 50 | #define bmDmaWidth32 0x80 51 | 52 | #define bmPRAM 1 53 | 54 | // ------------------------------------------------------------------------------------------------ 55 | // * SFRs 56 | // * ------------------------------------------------------------------------------------------------ 57 | // BYTE Register 58 | __sfr __at (0x80) P0 ; 59 | __sfr __at (0x90) P1 ; 60 | __sfr __at (0xA0) P2 ; 61 | __sfr __at (0xB0) P3 ; 62 | __sfr __at (0xD0) PSW ; 63 | __sfr __at (0xE0) ACC ; 64 | __sfr __at (0xF0) B ; 65 | __sfr __at (0x81) SP ; 66 | __sfr __at (0x82) DPL ; 67 | __sfr __at (0x83) DPH ; 68 | __sfr __at (0x87) PCON; 69 | __sfr __at (0x88) TCON; 70 | __sfr __at (0x89) TMOD; 71 | __sfr __at (0x8A) TL0 ; 72 | __sfr __at (0x8B) TL1 ; 73 | __sfr __at (0x8C) TH0 ; 74 | __sfr __at (0x8D) TH1 ; 75 | __sfr __at (0xA8) IE ; 76 | __sfr __at (0xB8) IP ; 77 | __sfr __at (0x98) SCON; 78 | __sfr __at (0x99) SBUF; 79 | 80 | /* BIT Register */ 81 | /* PSW */ 82 | __sbit __at (0xD7) CY ; 83 | __sbit __at (0xD6) AC ; 84 | __sbit __at (0xD5) F0 ; 85 | __sbit __at (0xD4) RS1 ; 86 | __sbit __at (0xD3) RS0 ; 87 | __sbit __at (0xD2) OV ; 88 | __sbit __at (0xD0) P ; 89 | 90 | /* TCON */ 91 | __sbit __at (0x8F) TF1 ; 92 | __sbit __at (0x8E) TR1 ; 93 | __sbit __at (0x8D) TF0 ; 94 | __sbit __at (0x8C) TR0 ; 95 | __sbit __at (0x8B) IE1 ; 96 | __sbit __at (0x8A) IT1 ; 97 | __sbit __at (0x89) IE0 ; 98 | __sbit __at (0x88) IT0 ; 99 | 100 | /* IE */ 101 | __sbit __at (0xAF) EA ; 102 | __sbit __at (0xAC) ES ; 103 | __sbit __at (0xAB) ET1 ; 104 | __sbit __at (0xAA) EX1 ; 105 | __sbit __at (0xA9) ET0 ; 106 | __sbit __at (0xA8) EX0 ; 107 | 108 | /* IP */ 109 | __sbit __at (0xBC) PS ; 110 | __sbit __at (0xBB) PT1 ; 111 | __sbit __at (0xBA) PX1 ; 112 | __sbit __at (0xB9) PT0 ; 113 | __sbit __at (0xB8) PX0 ; 114 | 115 | /* P3 */ 116 | __sbit __at (0xB7) RD ; 117 | __sbit __at (0xB6) WR ; 118 | __sbit __at (0xB5) T1 ; 119 | __sbit __at (0xB4) T0 ; 120 | __sbit __at (0xB3) INT1; 121 | __sbit __at (0xB2) INT0; 122 | __sbit __at (0xB1) TXD ; 123 | __sbit __at (0xB0) RXD ; 124 | 125 | /* SCON */ 126 | __sbit __at (0x9F) SM0 ; 127 | __sbit __at (0x9E) SM1 ; 128 | __sbit __at (0x9D) SM2 ; 129 | __sbit __at (0x9C) REN ; 130 | __sbit __at (0x9B) TB8 ; 131 | __sbit __at (0x9A) RB8 ; 132 | __sbit __at (0x99) TI ; 133 | __sbit __at (0x98) RI ; 134 | 135 | // ------------------------------------------------------------------------------------------------ 136 | // Xdata F000-F3FF USB Registers 137 | // ------------------------------------------------------------------------------------------------ 138 | // some banking registers switching 139 | // value: 0-7, default: 0 140 | __xdata __at 0xF000 volatile BYTE REGBANK; 141 | __xdata __at 0xF008 volatile BYTE USBCTL; 142 | __xdata __at 0xF009 volatile BYTE USBSTAT; 143 | __xdata __at 0xF027 volatile BYTE USBIRQ; 144 | __xdata __at 0xF020 volatile BYTE EPIRQ; 145 | __xdata __at 0xF030 volatile BYTE EPIE; 146 | __xdata __at 0xF048 volatile BYTE EP0CS; 147 | __xdata __at 0xF0B8 volatile BYTE SETUPDAT[8]; 148 | 149 | typedef struct 150 | { 151 | BYTE r0,r1,r2,r3,r4; 152 | BYTE ptr_l, ptr_m, ptr_h; //buffer ptr = buf_pa>>8 153 | BYTE r8,r9; 154 | BYTE ofs; // buffer offset, data addr will be ptr<<8 + ofs*0x200 155 | BYTE rB; 156 | BYTE len_l, len_m, len_h; //C,D,E 157 | BYTE rF,r10,r11,r12; 158 | BYTE cs; //13 159 | BYTE r14,r15,r16,r17,r18,r19; 160 | BYTE fifo_count; 161 | BYTE r1B; 162 | BYTE fifo; //1C 163 | } EPREGS; 164 | 165 | __xdata __at 0xF1C0 volatile EPREGS EP0; 166 | __xdata __at 0xF200 volatile EPREGS EP1; 167 | __xdata __at 0xF240 volatile EPREGS EP2; 168 | __xdata __at 0xF280 volatile EPREGS EP3; 169 | __xdata __at 0xF2C0 volatile EPREGS EP4; 170 | 171 | typedef struct 172 | { 173 | BYTE raw_cmd; 174 | BYTE u1[3]; 175 | BYTE raw_addr; 176 | BYTE u5[3]; 177 | BYTE raw_data; 178 | BYTE r9; 179 | BYTE uA[2]; 180 | BYTE rC; 181 | BYTE uD[3]; 182 | BYTE r10; 183 | BYTE u11[7]; 184 | BYTE r18; 185 | BYTE u19[5]; 186 | BYTE status; // .0 - R/nB 187 | BYTE u1F[0x19]; 188 | BYTE r38, r39, r3A; 189 | BYTE u3B; 190 | BYTE r3C, r3D; 191 | BYTE u3E[2]; 192 | BYTE r40; 193 | BYTE dma_size; // DMA size in KB 194 | BYTE r42; 195 | BYTE dma_mode; // DMA modes 196 | BYTE u44[3]; 197 | BYTE r47; 198 | BYTE u48[0x14]; 199 | BYTE r5C; // nand command 200 | // DMA command. |=1 to go, wait until .0 cleared 201 | BYTE dma_cmd; 202 | BYTE u61[0x0B]; 203 | BYTE dma1_page; // DMA1 start page. Autoincrements 204 | BYTE u6D[3]; 205 | BYTE dma0_page; // DMA0 start page. Autoincrements 206 | BYTE u71[3]; 207 | // DMA1 PA. This pseudo reg sets dma1_page actually. RAZ 208 | BYTE dma1_ptr0, dma1_ptr1, dma1_ptr2, dma1_ptr3; 209 | // DMA0 PA. This pseudo reg sets w_dma_page actually. RAZ 210 | BYTE dma0_ptr0, dma0_ptr1, dma0_ptr2, dma0_ptr3; 211 | BYTE u7C[4]; 212 | BYTE r80; 213 | BYTE u81[0x1B]; 214 | BYTE page_size_l, page_size_h; // 9C full page size with spare 215 | BYTE r9E, r9F; 216 | BYTE uA0[0x4C]; 217 | BYTE rEC; 218 | BYTE uED[0x13]; 219 | } NANDREGS; 220 | 221 | __xdata __at 0xF400 volatile NANDREGS NFC0; 222 | __xdata __at 0xF500 volatile NANDREGS NFC1; 223 | 224 | __xdata __at 0xF608 volatile BYTE NANDCSOUT; 225 | __xdata __at 0xF618 volatile BYTE NANDCSDIR; 226 | //F638, F639 - scrambler control 227 | //F638 | 18 & 7F - turn off descrambler 228 | __xdata __at 0xF700 volatile NANDREGS NFCX; 229 | 230 | // DMA copy source / fill destination physical address 231 | __xdata __at 0xF900 volatile BYTE DMASRCL; 232 | __xdata __at 0xF901 volatile BYTE DMASRCM; 233 | __xdata __at 0xF902 volatile BYTE DMASRCH; 234 | 235 | // DMA copy destination physical address 236 | __xdata __at 0xF904 volatile BYTE DMADSTL; 237 | __xdata __at 0xF905 volatile BYTE DMADSTM; 238 | __xdata __at 0xF906 volatile BYTE DMADSTH; 239 | 240 | // DMA copy size in bytes (always in bytes, regardless of cmd width) 241 | __xdata __at 0xF908 volatile BYTE DMASIZEL; 242 | __xdata __at 0xF909 volatile BYTE DMASIZEM; 243 | __xdata __at 0xF90A volatile BYTE DMASIZEH; 244 | 245 | // DMA fill value 246 | __xdata __at 0xF90C volatile BYTE DMAFILL0; 247 | __xdata __at 0xF90D volatile BYTE DMAFILL1; 248 | __xdata __at 0xF90E volatile BYTE DMAFILL2; 249 | __xdata __at 0xF90F volatile BYTE DMAFILL3; 250 | 251 | // DMA command 252 | __xdata __at 0xF930 volatile BYTE DMACMD; 253 | 254 | // ------------------------------------------------------------------------------------------------ 255 | // Xdata FA00-FAFF SYSTEM Registers 256 | // ------------------------------------------------------------------------------------------------ 257 | __xdata __at 0xFA14 volatile BYTE GPIO0DIR; 258 | __xdata __at 0xFA15 volatile BYTE GPIO0OUT; 259 | __xdata __at 0xFA38 volatile BYTE WARMSTATUS; 260 | 261 | // XDATA banking 262 | // XDATA consists of 3 mapped areas: BANK0,1,2 263 | // BANK0 start is fixed at 0000, BANK1,2 starts at variable addresses 264 | // in case of overlapped addresses a bank with higher number has higher priority 265 | 266 | // xdata BANK0 mapping registers 267 | // maps XDATA VA 0000 to PA=BANK0PAH:L<<9, size - up to BANK1/2 268 | __xdata __at 0xFA40 volatile BYTE BANK0PAL; 269 | __xdata __at 0xFA41 volatile BYTE BANK0PAH; 270 | 271 | // xdata BANK1 mapping registers 272 | // maps XDATA VA=(BANK1VA & 0xFE)<<8 to PA=BANK1PAH:L<<9, size - up to BANK2 273 | __xdata __at 0xFA42 volatile BYTE BANK1VA; 274 | __xdata __at 0xFA43 volatile BYTE BANK1PAL; 275 | __xdata __at 0xFA44 volatile BYTE BANK1PAH; 276 | 277 | // xdata BANK2 mapping registers 278 | // maps XDATA VA=(BANK2VA & 0xFE)<<8 to PA=BANK2PAH:L<<9, size - up to F000 279 | __xdata __at 0xFA45 volatile BYTE BANK2VA; 280 | __xdata __at 0xFA46 volatile BYTE BANK2PAL; 281 | __xdata __at 0xFA47 volatile BYTE BANK2PAH; 282 | 283 | // PRAM/PROM switching with restart 284 | // value: bit0 =0 - run from PROM, =1 - run from PRAM. Changing this bit causes CPU restart! 285 | __xdata __at 0xFA48 volatile BYTE PRAMCTL; 286 | 287 | #endif 288 | -------------------------------------------------------------------------------- /templates/BNdummy.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/templates/BNdummy.bin -------------------------------------------------------------------------------- /templates/FWdummy.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/templates/FWdummy.bin -------------------------------------------------------------------------------- /tools/hex2bin.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/tools/hex2bin.exe -------------------------------------------------------------------------------- /tools/sfk.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brandonlw/Psychson/4522989aac27aada5f522675b33a2bde63a13b30/tools/sfk.exe --------------------------------------------------------------------------------