diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3e1967b --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +**/bin/Debug/* +**/obj/Debug/* +**/bin/Release/* +**/obj/Release/* +firmware/bin/* +patch/bin/* +patch/equates.h +tools/* diff --git a/DriveCom/DriveCom.sln b/DriveCom/DriveCom.sln new file mode 100644 index 0000000..be504e7 --- /dev/null +++ b/DriveCom/DriveCom.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DriveCom", "DriveCom\DriveCom.csproj", "{25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/DriveCom/DriveCom.v11.suo b/DriveCom/DriveCom.v11.suo new file mode 100644 index 0000000..cfa5516 Binary files /dev/null and b/DriveCom/DriveCom.v11.suo differ diff --git a/DriveCom/DriveCom/App.config b/DriveCom/DriveCom/App.config new file mode 100644 index 0000000..58262a1 --- /dev/null +++ b/DriveCom/DriveCom/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/DriveCom/DriveCom/DriveCom.csproj b/DriveCom/DriveCom/DriveCom.csproj new file mode 100644 index 0000000..13695be --- /dev/null +++ b/DriveCom/DriveCom/DriveCom.csproj @@ -0,0 +1,61 @@ + + + + + Debug + AnyCPU + {25CF4003-4DF8-4F3C-B9B5-50252C2CD2C2} + Exe + Properties + DriveCom + DriveCom + v4.0 + 512 + + + + AnyCPU + true + full + false + ..\..\tools\ + DEBUG;TRACE + prompt + 4 + true + + + AnyCPU + pdbonly + true + ..\..\tools\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DriveCom/DriveCom/DriveCom.csproj.user b/DriveCom/DriveCom/DriveCom.csproj.user new file mode 100644 index 0000000..9934927 --- /dev/null +++ b/DriveCom/DriveCom/DriveCom.csproj.user @@ -0,0 +1,9 @@ + + + + /drive=E /burner=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\BN03V104M.BIN /firmware=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\FW03FF01V10353M.BIN + + + /drive=E /burner="C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\BN03V104M.BIN" + + \ No newline at end of file diff --git a/DriveCom/DriveCom/PhisonDevice.cs b/DriveCom/DriveCom/PhisonDevice.cs new file mode 100644 index 0000000..1398604 --- /dev/null +++ b/DriveCom/DriveCom/PhisonDevice.cs @@ -0,0 +1,374 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace DriveCom +{ + public class PhisonDevice + { + private char _driveLetter; + private SafeFileHandle _handle; + + public enum RunMode + { + Unknown, + BootMode, + Burner, + HardwareVerify, + Firmware + } + + [Flags] + public enum EFileAttributes : uint + { + Readonly = 0x00000001, + Hidden = 0x00000002, + System = 0x00000004, + Directory = 0x00000010, + Archive = 0x00000020, + Device = 0x00000040, + Normal = 0x00000080, + Temporary = 0x00000100, + SparseFile = 0x00000200, + ReparsePoint = 0x00000400, + Compressed = 0x00000800, + Offline = 0x00001000, + NotContentIndexed = 0x00002000, + Encrypted = 0x00004000, + Write_Through = 0x80000000, + Overlapped = 0x40000000, + NoBuffering = 0x20000000, + RandomAccess = 0x10000000, + SequentialScan = 0x08000000, + DeleteOnClose = 0x04000000, + BackupSemantics = 0x02000000, + PosixSemantics = 0x01000000, + OpenReparsePoint = 0x00200000, + OpenNoRecall = 0x00100000, + FirstPipeInstance = 0x00080000 + } + + [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)] + public static extern SafeFileHandle CreateFile( + string fileName, + [MarshalAs(UnmanagedType.U4)] FileAccess fileAccess, + [MarshalAs(UnmanagedType.U4)] FileShare fileShare, + IntPtr securityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, + [MarshalAs(UnmanagedType.U4)] EFileAttributes flags, + IntPtr template); + + [DllImport("kernel32.dll")] + static public extern int CloseHandle(SafeFileHandle hObject); + + public const byte SCSI_IOCTL_DATA_OUT = 0; + public const byte SCSI_IOCTL_DATA_IN = 1; + + [StructLayout(LayoutKind.Sequential)] + class SCSI_PASS_THROUGH_DIRECT + { + private const int _CDB_LENGTH = 16; + + public short Length; + public byte ScsiStatus; + public byte PathId; + public byte TargetId; + public byte Lun; + public byte CdbLength; + public byte SenseInfoLength; + public byte DataIn; + public int DataTransferLength; + public int TimeOutValue; + public IntPtr DataBuffer; + public uint SenseInfoOffset; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _CDB_LENGTH)] + public byte[] Cdb; + + public SCSI_PASS_THROUGH_DIRECT() + { + Cdb = new byte[_CDB_LENGTH]; + } + }; + + [StructLayout(LayoutKind.Sequential)] + class SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER + { + private const int _SENSE_LENGTH = 32; + internal SCSI_PASS_THROUGH_DIRECT sptd = new SCSI_PASS_THROUGH_DIRECT(); + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = _SENSE_LENGTH)] + internal byte[] sense; + + public SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER() + { + sense = new byte[_SENSE_LENGTH]; + } + }; + + [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true, CharSet = CharSet.Auto)] + static extern bool DeviceIoControl(IntPtr hDevice, uint dwIoControlCode, + IntPtr lpInBuffer, uint nInBufferSize, + IntPtr lpOutBuffer, uint nOutBufferSize, + out uint lpBytesReturned, IntPtr lpOverlapped); + + /// + /// Creates a reference to a device with a Phison USB controller. + /// + /// The Windows drive letter representing the device. + public PhisonDevice(char driveLetter) + { + _driveLetter = driveLetter; + } + + /// + /// Opens a connection to the device. + /// + public void Open() + { + _handle = CreateFile(string.Format("\\\\.\\{0}:", _driveLetter), FileAccess.ReadWrite, FileShare.ReadWrite, + IntPtr.Zero, FileMode.Open, EFileAttributes.NoBuffering, IntPtr.Zero); + } + + public byte[] RequestVendorInfo() + { + var data = SendCommand(new byte[] { 0x06, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }, + 512 + 16); + byte[] ret = null; + + if (data != null) + { + ret = data.Take(512).ToArray(); + } + + return ret; + } + + public ushort? GetChipType() + { + ushort? ret = null; + var info = RequestVendorInfo(); + + if (info != null) + { + if (info[0x17A] == (byte)'V' && info[0x17B] == (byte)'R') + { + var data = info.Skip(0x17E).Take(2).ToArray(); + ret = (ushort)((data[0] << 8) | data[1]); + } + } + + return ret; + } + + public RunMode GetRunMode() + { + var ret = RunMode.Unknown; + var info = RequestVendorInfo(); + + if (info != null) + { + if (info[0x17A] == (byte)'V' && info[0x17B] == (byte)'R') + { + //TODO: Fix this, this is a dumb way of detecting it + switch (ASCIIEncoding.ASCII.GetString(info.Skip(0xA0).Take(8).ToArray())) + { + case " PRAM ": + ret = RunMode.BootMode; + break; + case " FW BURN": + ret = RunMode.Burner; + break; + case " HV TEST": + ret = RunMode.HardwareVerify; + break; + default: + ret = RunMode.Firmware; + break; + } + } + } + + return ret; + } + + public void JumpToPRAM() + { + SendCommand(new byte[] { 0x06, 0xB3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + } + + public void JumpToBootMode() + { + SendCommand(new byte[] { 0x06, 0xBF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + } + + public void TransferFile(byte[] data) + { + TransferFile(data, 0x03, 0x02); + } + + public void TransferFile(byte[] data, byte header, byte body) + { + var size = data.Length - 1024; + + //Send header + SendCommand(new byte[] { 0x06, 0xB1, header, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, data.Take(0x200).ToArray()); + + //Get response + var response = SendCommand(new byte[] { 0x06, 0xB0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); + if (response == null || response[0] != 0x55) + { + throw new InvalidOperationException("Header not accepted"); + } + + //Send body + int address = 0; + while (size > 0) + { + int chunkSize; + if (size > 0x8000) + { + chunkSize = 0x8000; + } + else + { + chunkSize = size; + } + + int cmdAddress = address >> 9; + int cmdChunk = chunkSize >> 9; + SendCommand(new byte[] { 0x06, 0xB1, body, (byte)((cmdAddress >> 8) & 0xFF), (byte)(cmdAddress & 0xFF), + 0x00, 0x00, (byte)((cmdChunk >> 8) & 0xFF), (byte)(cmdChunk & 0xFF), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + data.Skip(address + 0x200).Take(chunkSize).ToArray()); + + //Get response + var r = SendCommand(new byte[] { 0x06, 0xB0, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 8); + if (r == null || r[0] != 0xA5) + { + throw new InvalidOperationException("Body not accepted"); + } + + address += chunkSize; + size -= chunkSize; + } + } + + /// + /// Sends command with no attached data and returns expected response. + /// + /// + /// + /// + public byte[] SendCommand(byte[] cmd, int bytesExpected) + { + return _SendCommand(_handle, cmd, null, bytesExpected); + } + + /// + /// Sends command with no attached data and no response. + /// + /// + public void SendCommand(byte[] cmd) + { + SendCommand(cmd, null); + } + + /// + /// Sends command with attached data and no response. + /// + /// + /// + public void SendCommand(byte[] cmd, byte[] data) + { + _SendCommand(_handle, cmd, data, 0); + } + + /// + /// Closes the connection to the device. + /// + public void Close() + { + if (_handle != null && !_handle.IsClosed) + { + _handle.Close(); + } + } + + private static byte[] _SendCommand(SafeFileHandle handle, byte[] cmd, byte[] data, int bytesExpected) + { + const int IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x4D014; + const int TIMEOUT_SECS = 30; + SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER scsi = null; + IntPtr inBuffer = IntPtr.Zero; + byte[] ret = null; + + try + { + scsi = new SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER(); + scsi.sptd.Length = (short)Marshal.SizeOf(scsi.sptd); + scsi.sptd.TimeOutValue = TIMEOUT_SECS; + scsi.sptd.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER), "sense"); + scsi.sptd.SenseInfoLength = (byte)scsi.sense.Length; + scsi.sptd.CdbLength = (byte)cmd.Length; + Array.Copy(cmd, scsi.sptd.Cdb, cmd.Length); + scsi.sptd.DataIn = data != null && data.Length > 0 ? SCSI_IOCTL_DATA_OUT : SCSI_IOCTL_DATA_IN; + scsi.sptd.DataTransferLength = data != null && data.Length > 0 ? data.Length : bytesExpected; + scsi.sptd.DataBuffer = Marshal.AllocHGlobal(scsi.sptd.DataTransferLength); + if (data != null && data.Length > 0) + { + Marshal.Copy(data, 0, scsi.sptd.DataBuffer, data.Length); + } + + uint bytesReturned; + inBuffer = Marshal.AllocHGlobal(Marshal.SizeOf(scsi)); + var size = (uint)Marshal.SizeOf(scsi); + Marshal.StructureToPtr(scsi, inBuffer, false); + if (!DeviceIoControl(handle.DangerousGetHandle(), IOCTL_SCSI_PASS_THROUGH_DIRECT, + inBuffer, size, inBuffer, size, out bytesReturned, IntPtr.Zero)) + { + //Whoops, do something with the error code + int last = Marshal.GetLastWin32Error(); + throw new InvalidOperationException("DeviceIoControl failed: " + last.ToString("X04")); + } + else + { + if (scsi.sptd.ScsiStatus != 0) + { + //Whoops, do something with the error code + throw new InvalidOperationException("SCSI command failed: " + scsi.sptd.ScsiStatus.ToString("X02")); + } + else + { + //Success, marshal back any data we received + if (scsi.sptd.DataTransferLength > 0) + { + ret = new byte[scsi.sptd.DataTransferLength]; + Marshal.Copy(scsi.sptd.DataBuffer, ret, 0, ret.Length); + } + } + } + } + finally + { + /* Free any unmanaged resources */ + + if (scsi != null && scsi.sptd.DataBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(scsi.sptd.DataBuffer); + } + + if (inBuffer != IntPtr.Zero) + { + Marshal.FreeHGlobal(inBuffer); + } + } + + return ret; + } + } +} diff --git a/DriveCom/DriveCom/PhisonDo.csproj.user b/DriveCom/DriveCom/PhisonDo.csproj.user new file mode 100644 index 0000000..7b718e3 --- /dev/null +++ b/DriveCom/DriveCom/PhisonDo.csproj.user @@ -0,0 +1,6 @@ + + + + /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" + + \ No newline at end of file diff --git a/DriveCom/DriveCom/Properties/AssemblyInfo.cs b/DriveCom/DriveCom/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..96d2c25 --- /dev/null +++ b/DriveCom/DriveCom/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("PhisonDo")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("PhisonDo")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ebfd9a94-1fd1-4595-a864-a3525ff4c875")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DriveCom/DriveCom/Startup.cs b/DriveCom/DriveCom/Startup.cs new file mode 100644 index 0000000..a54a342 --- /dev/null +++ b/DriveCom/DriveCom/Startup.cs @@ -0,0 +1,428 @@ +using Microsoft.Win32.SafeHandles; +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace DriveCom +{ + class Startup + { + private const int _WAIT_TIME_MS = 2000; + private static PhisonDevice _device = null; + private static string _burner; + private static string _firmware; + private static string _password; + + public enum Action + { + None, + GetInfo, + SetPassword, + DumpFirmware, + SetBootMode, + SendExecutable, + SendFirmware + } + + public enum ExitCode + { + Success = 0, + Failure = 1 + } + + static void Main(string[] args) + { + try + { + Environment.ExitCode = (int)ExitCode.Success; + + var action = Action.None; + string drive = string.Empty; + + foreach (var arg in args) + { + var parts = arg.TrimStart(new char[] { '/' }).Split(new char[] { '=' }, + StringSplitOptions.RemoveEmptyEntries); + switch (parts[0].ToLower()) + { + case "action": + { + action = (Action)Enum.Parse(typeof(Action), parts[1]); + break; + } + case "drive": + { + drive = parts[1]; + break; + } + case "burner": + { + _burner = parts[1]; + break; + } + case "firmware": + { + _firmware = parts[1]; + break; + } + case "password": + { + _password = parts[1]; + break; + } + default: + { + break; + } + } + } + + if (!string.IsNullOrEmpty(drive)) + { + _OpenDrive(drive); + } + + if (action != Action.None) + { + Console.WriteLine("Action specified: " + action.ToString()); + + switch (action) + { + case Action.DumpFirmware: + { + _DumpFirmware(_firmware); + break; + } + case Action.GetInfo: + { + _GetInfo(); + break; + } + case Action.SendExecutable: + { + _ExecuteImage(_burner); + break; + } + case Action.SendFirmware: + { + _SendFirmware(); + break; + } + case Action.SetBootMode: + { + _device.JumpToBootMode(); + Thread.Sleep(_WAIT_TIME_MS); + break; + } + case Action.SetPassword: + { + _SendPassword(_password); + break; + } + default: + { + throw new ArgumentException("No/invalid action specified"); + } + } + } + else + { + Console.WriteLine("No action specified, entering console."); + + bool exiting = false; + while (!exiting) + { + Console.Write(">"); + var line = Console.ReadLine(); + var @params = line.Split(new char[] { ' ' }); + + try + { + switch (@params[0].ToLower()) + { + case "open": + { + _OpenDrive(@params[1]); + break; + } + case "close": + { + _CloseDrive(); + break; + } + case "mode": + { + Console.WriteLine("Mode: " + _GetInfo().ToString()); + break; + } + case "info": + { + var data = _device.RequestVendorInfo(); + Console.WriteLine(string.Format("Info: {0}...", BitConverter.ToString(data, 0, 16))); + break; + } + case "password": + { + _SendPassword(@params[1]); + break; + } + case "dump_xram": + { + var address = 0; + var data = new byte[0xF000]; + for (int i = 0; i < data.Length; i++) + { + var result = _device.SendCommand(new byte[] { 0x06, 0x06, + (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); + data[address] = result[0]; + address++; + } + + File.WriteAllBytes(@params[1], data); + break; + } + case "dump_firmware": + { + _DumpFirmware(@params[1]); + break; + } + case "nand_read": + { + var address = Convert.ToInt32(@params[1], 16); + var size = Convert.ToInt32(@params[2], 16); + var result = _device.SendCommand(new byte[] { 0x06, 0xB2, 0x10, + (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, + (byte)((size >> 8) & 0xFF), (byte)(size & 0xFF) }, size * 512); + Console.WriteLine(string.Format("Data: {0}...", BitConverter.ToString(result, 0, 16))); + break; + } + case "boot": + { + _device.JumpToBootMode(); + Thread.Sleep(_WAIT_TIME_MS); + break; + } + case "set_burner": + { + _burner = @params[1]; + break; + } + case "set_firmware": + { + _firmware = @params[1]; + break; + } + case "burner": + { + _ExecuteImage(_burner); + break; + } + case "firmware": + { + _SendFirmware(); + break; + } + case "peek": + { + var address = Convert.ToInt32(@params[1], 16); + var result = _device.SendCommand(new byte[] { 0x06, 0x06, + (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); + Console.WriteLine("Value: " + result[0].ToString("X02")); + break; + } + case "poke": + { + var address = Convert.ToInt32(@params[1], 16); + var value = Convert.ToInt32(@params[2], 16); + _device.SendCommand(new byte[] { 0x06, 0x07, + (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), (byte)value, 0x00, 0x00 }, 1); + break; + } + case "ipeek": + { + var address = Convert.ToInt32(@params[1], 16); + var result = _device.SendCommand(new byte[] { 0x06, 0x08, + (byte)(address & 0xFF), 0x00, 0x00, 0x00, 0x00 }, 1); + Console.WriteLine("Value: " + result[0].ToString("X02")); + break; + } + case "ipoke": + { + var address = Convert.ToInt32(@params[1], 16); + var value = Convert.ToInt32(@params[2], 16); + _device.SendCommand(new byte[] { 0x06, 0x09, + (byte)(address & 0xFF), (byte)value, 0x00, 0x00 }, 1); + break; + } + case "quit": + case "exit": + { + exiting = true; + break; + } + default: + Console.WriteLine("Invalid command: " + @params[0]); + break; + } + } + catch (Exception ex) + { + Console.WriteLine("ERROR: " + ex.ToString()); + } + } + + Console.WriteLine("Done."); + } + } + catch (Exception ex) + { + Environment.ExitCode = (int)ExitCode.Failure; + + Console.WriteLine("FATAL: " + ex.ToString()); + } + finally + { + if (_device != null) + { + _device.Close(); + } + } + } + + private static void _OpenDrive(string drive) + { + _CloseDrive(); + + _device = new PhisonDevice(drive[0]); + _device.Open(); + } + + private static void _CloseDrive() + { + if (_device != null) + { + _device.Close(); + _device = null; + } + } + + private static void _DumpFirmware(string fileName) + { + var address = 0; + var data = new byte[0x32400]; + var header = new byte[] { 0x42, 0x74, 0x50, 0x72, 0x61, 0x6D, 0x43, 0x64, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x10, 0x0B, 0x18 }; + Array.Copy(header, 0, data, 0, header.Length); + while (address * 0x200 < data.Length) + { + var length = Math.Min(0x40 * 512, (data.Length - 0x400) - (address * 0x200)); + var temp = length / 512; + var result = _device.SendCommand(new byte[] { 0x06, 0xB2, 0x10, + (byte)((address >> 8) & 0xFF), (byte)(address & 0xFF), 0x00, 0x00, + (byte)((temp >> 8) & 0xFF), (byte)(temp & 0xFF) }, length); + Array.Copy(result.Take(length).ToArray(), 0, data, 0x200 + address * 512, length); + address += 0x40; + } + + var footer = new byte[] { 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x6D, + 0x70, 0x20, 0x6D, 0x61, 0x72, 0x6B, 0x00, 0x03, 0x01, 0x00, 0x10, 0x01, 0x04, 0x10, 0x42 }; + Array.Copy(footer, 0, data, data.Length - 0x200, footer.Length); + File.WriteAllBytes(fileName, data); + } + + private static void _SendPassword(string password) + { + var data = new byte[0x200]; + var pw = ASCIIEncoding.ASCII.GetBytes(password); + Array.Copy(pw, 0, data, 0x10, pw.Length); + _device.SendCommand(new byte[] { 0x0E, 0x00, 0x01, 0x55, 0xAA, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, data); + } + + private static void _SendFirmware() + { + var mode = _GetInfo(); + if (mode != PhisonDevice.RunMode.Burner) + { + if (mode != PhisonDevice.RunMode.BootMode) + { + Console.WriteLine("Switching to boot mode..."); + _device.JumpToBootMode(); + Thread.Sleep(_WAIT_TIME_MS); + } + + _ExecuteImage(_burner); + } + + _RunFirmware(_firmware); + } + + private static PhisonDevice.RunMode _GetInfo() + { + Console.WriteLine("Gathering information..."); + Console.WriteLine("Reported chip type: " + _device.GetChipType().GetValueOrDefault().ToString("X04")); + + var ret = _device.GetRunMode(); + Console.WriteLine("Mode: " + ret.ToString()); + + return ret; + } + + private static void _ExecuteImage(string fileName) + { + //Read image + var file = new FileStream(fileName, FileMode.Open); + var fileData = new byte[file.Length]; + file.Read(fileData, 0, fileData.Length); + file.Close(); + + //Load it + _device.TransferFile(fileData); + _device.JumpToPRAM(); + + //Wait a little bit + Thread.Sleep(_WAIT_TIME_MS); + } + + private static void _RunFirmware(string fileName) + { + //Get file data + var fw = new FileStream(fileName, FileMode.Open); + var data = new byte[fw.Length]; + fw.Read(data, 0, data.Length); + fw.Close(); + + //TODO: Find out what this actually does... + //Console.WriteLine("Sending scary B7 command (takes several seconds)..."); + //_device.SendCommand(new byte[] { 0x06, 0xB7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + + Console.WriteLine("Rebooting..."); + _device.JumpToBootMode(); + Thread.Sleep(_WAIT_TIME_MS); + + Console.WriteLine("Sending firmware..."); + _device.TransferFile(data, 0x01, 0x00); + var ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); + Thread.Sleep(_WAIT_TIME_MS); + _device.TransferFile(data, 0x03, 0x02); + ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); + Thread.Sleep(_WAIT_TIME_MS); + ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); + Thread.Sleep(_WAIT_TIME_MS); + ret = _device.SendCommand(new byte[] { 0x06, 0xEE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 }, 64 + 8); + Thread.Sleep(_WAIT_TIME_MS); + + Console.WriteLine("Executing..."); + _device.JumpToPRAM(); + Thread.Sleep(_WAIT_TIME_MS); + + //Display new mode, if we can actually get it + Console.WriteLine("Mode: " + _device.GetRunMode().ToString()); + } + } +} diff --git a/EmbedPayload/EmbedPayload.exe.config b/EmbedPayload/EmbedPayload.exe.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/EmbedPayload/EmbedPayload.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/EmbedPayload/EmbedPayload.sln b/EmbedPayload/EmbedPayload.sln new file mode 100644 index 0000000..d41bf9a --- /dev/null +++ b/EmbedPayload/EmbedPayload.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EmbedPayload", "EmbedPayload\EmbedPayload.csproj", "{E2381629-180B-44DE-8702-B63B4699A587}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E2381629-180B-44DE-8702-B63B4699A587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2381629-180B-44DE-8702-B63B4699A587}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2381629-180B-44DE-8702-B63B4699A587}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2381629-180B-44DE-8702-B63B4699A587}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/EmbedPayload/EmbedPayload.v11.suo b/EmbedPayload/EmbedPayload.v11.suo new file mode 100644 index 0000000..47ca141 Binary files /dev/null and b/EmbedPayload/EmbedPayload.v11.suo differ diff --git a/EmbedPayload/EmbedPayload.vshost.exe.config b/EmbedPayload/EmbedPayload.vshost.exe.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/EmbedPayload/EmbedPayload.vshost.exe.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/EmbedPayload/EmbedPayload/App.config b/EmbedPayload/EmbedPayload/App.config new file mode 100644 index 0000000..8e15646 --- /dev/null +++ b/EmbedPayload/EmbedPayload/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/EmbedPayload/EmbedPayload/EmbedPayload.csproj b/EmbedPayload/EmbedPayload/EmbedPayload.csproj new file mode 100644 index 0000000..ffede20 --- /dev/null +++ b/EmbedPayload/EmbedPayload/EmbedPayload.csproj @@ -0,0 +1,58 @@ + + + + + Debug + AnyCPU + {E2381629-180B-44DE-8702-B63B4699A587} + Exe + Properties + EmbedPayload + EmbedPayload + v4.5 + 512 + + + AnyCPU + true + full + false + ..\..\tools\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\tools\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/EmbedPayload/EmbedPayload/Properties/AssemblyInfo.cs b/EmbedPayload/EmbedPayload/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..612a796 --- /dev/null +++ b/EmbedPayload/EmbedPayload/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("EmbedPayload")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Toshiba")] +[assembly: AssemblyProduct("EmbedPayload")] +[assembly: AssemblyCopyright("Copyright © Toshiba 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5cd1f91a-6190-490e-a5c8-6d200a7e00db")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/EmbedPayload/EmbedPayload/Startup.cs b/EmbedPayload/EmbedPayload/Startup.cs new file mode 100644 index 0000000..53e33d6 --- /dev/null +++ b/EmbedPayload/EmbedPayload/Startup.cs @@ -0,0 +1,92 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace EmbedPayload +{ + class Startup + { + public enum ExitCode + { + Success = 0, + Failure = 1 + } + + static void Main(string[] args) + { + if (args.Length != 2) + { + Console.WriteLine("Usage: [payload BIN] [firmware image]"); + return; + } + + try + { + //Assume success at first + Environment.ExitCode = (int)ExitCode.Success; + + //Read all bytes from input file + var payload = File.ReadAllBytes(args[0]); + + //Read all bytes from output file: + var stream = new FileStream(args[1], FileMode.Open, FileAccess.ReadWrite); + var header = new byte[0x200]; + stream.Read(header, 0, header.Length); + var data = new byte[0x6000]; + stream.Read(data, 0, data.Length); + + // Look for 0x12345678 + var signature = new byte[] { 0x12, 0x34, 0x56, 0x78 }; + int? address = null; + for (int i = 0; i < data.Length; i++) + { + bool match = true; + for (int j = 0; j < signature.Length; j++) + { + if (data[i + j] != signature[j]) + { + match = false; + break; + } + } + + if (match) + { + address = i; + break; + } + } + + // When found, overwrite with input data + if (address.HasValue) + { + if ((0x200 + address.Value) >= 0x6000) + { + throw new InvalidOperationException("Insufficient memory to inject file!"); + } + + stream.Seek(0x200 + address.Value, SeekOrigin.Begin); + stream.Write(payload, 0, payload.Length); + + //Save output file back out + stream.Close(); + Console.WriteLine("File updated."); + } + else + { + Console.WriteLine("Signature not found!"); + } + } + catch (Exception ex) + { + //Uh-oh + Environment.ExitCode = (int)ExitCode.Failure; + + Console.WriteLine("FATAL: " + ex.ToString()); + } + } + } +} diff --git a/Injector/Injector.sln b/Injector/Injector.sln new file mode 100644 index 0000000..5c45d9a --- /dev/null +++ b/Injector/Injector.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Injector", "Injector\Injector.csproj", "{41480B6F-9051-43D1-9484-30A265D09D5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {41480B6F-9051-43D1-9484-30A265D09D5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {41480B6F-9051-43D1-9484-30A265D09D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {41480B6F-9051-43D1-9484-30A265D09D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {41480B6F-9051-43D1-9484-30A265D09D5D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Injector/Injector.v11.suo b/Injector/Injector.v11.suo new file mode 100644 index 0000000..cb55d50 Binary files /dev/null and b/Injector/Injector.v11.suo differ diff --git a/Injector/Injector/App.config b/Injector/Injector/App.config new file mode 100644 index 0000000..58262a1 --- /dev/null +++ b/Injector/Injector/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/Injector/Injector/DoPatch.csproj.user b/Injector/Injector/DoPatch.csproj.user new file mode 100644 index 0000000..0f80b6e --- /dev/null +++ b/Injector/Injector/DoPatch.csproj.user @@ -0,0 +1,6 @@ + + + + /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" + + \ No newline at end of file diff --git a/Injector/Injector/FirmwareImage.cs b/Injector/Injector/FirmwareImage.cs new file mode 100644 index 0000000..b89eb11 --- /dev/null +++ b/Injector/Injector/FirmwareImage.cs @@ -0,0 +1,150 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Injector +{ + public class FirmwareImage + { + private string _fileName; + private byte[] _header; + private Dictionary _sections; + private byte[] _footer; + + public FirmwareImage(string fileName) + { + _fileName = fileName; + _header = new byte[0x200]; + _sections = new Dictionary(); + _sections.Add(FirmwareSection.Base, new byte[0x6000]); + } + + public byte[] GetSection(FirmwareSection section) + { + byte[] ret = null; + + if (_sections.ContainsKey(section)) + { + ret = _sections[section]; + } + + return ret; + } + + public void Open() + { + FirmwareSection i = 0; + + //Get the header and base page + var stream = new FileStream(_fileName, FileMode.Open); + var @base = GetSection(FirmwareSection.Base); + stream.Read(_header, 0, _header.Length); + stream.Read(@base, 0, @base.Length); + + //Read in all the sections + while ((stream.Length - stream.Position) > 0x200) + { + var data = new byte[0x4000]; + stream.Read(data, 0, data.Length); + _sections.Add(i++, data); + } + + //If we have a footer, read it in + if ((stream.Length - stream.Position) == 0x200) + { + _footer = new byte[0x200]; + stream.Read(_footer, 0, _footer.Length); + } + + //All done + stream.Close(); + } + + public bool FindPattern(byte?[] pattern, out FirmwareSection section, out int address) + { + return FindPattern(pattern, 0, out section, out address); + } + + public bool FindPattern(byte?[] pattern, int startingOffset, out FirmwareSection section, out int address) + { + bool ret = false; + section = FirmwareSection.Base; + address = 0; + + foreach (var s in _sections) + { + for (int i = startingOffset; i < s.Value.Length; i++) + { + bool match = true; + for (int j = 0; j < pattern.Length; j++) + { + if (((i + j) >= s.Value.Length) || + ((s.Value[i + j] != pattern[j]) && (pattern[j].HasValue))) + { + match = false; + break; + } + } + + if (match) + { + section = s.Key; + address = i; + ret = true; + break; + } + } + + if (ret) + { + break; + } + } + + return ret; + } + + public int FindLastFreeChunk(FirmwareSection section) + { + int ret = -1; + + if (_sections.ContainsKey(section)) + { + var data = _sections[section]; + var repeating = data[data.Length - 1]; + ret = data.Length - 2; + + while (data[ret] == repeating) + { + ret--; + if (ret < 0) + { + break; + } + } + } + + return ++ret; + } + + public void Save(string fileName) + { + var output = new FileStream(fileName, FileMode.Create); + output.Write(_header, 0, _header.Length); + foreach (var section in _sections.OrderBy(t => t.Key)) + { + output.Write(section.Value, 0, section.Value.Length); + } + + if (_footer != null) + { + output.Write(_footer, 0, _footer.Length); + } + + output.Close(); + } + } +} diff --git a/Injector/Injector/FirmwareSection.cs b/Injector/Injector/FirmwareSection.cs new file mode 100644 index 0000000..40c4c9d --- /dev/null +++ b/Injector/Injector/FirmwareSection.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Injector +{ + public enum FirmwareSection + { + None = -2, + Base = -1, + Section0 = 0x00, + Section1 = 0x01, + Section2 = 0x02, + Section3 = 0x03, + Section4 = 0x04, + Section5 = 0x05, + Section6 = 0x06, + Section7 = 0x07, + Section8 = 0x08, + Section9 = 0x09, + SectionA = 0x0A, + SectionB = 0x0B, + SectionC = 0x0C, + SectionD = 0x0D, + SectionE = 0x0E, + SectionF = 0x0F + } +} diff --git a/Injector/Injector/Injector.csproj b/Injector/Injector/Injector.csproj new file mode 100644 index 0000000..c51311b --- /dev/null +++ b/Injector/Injector/Injector.csproj @@ -0,0 +1,61 @@ + + + + + Debug + AnyCPU + {41480B6F-9051-43D1-9484-30A265D09D5D} + Exe + Properties + Injector + Injector + v4.0 + 512 + + + + AnyCPU + true + full + false + ..\..\tools\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + ..\..\tools\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Injector/Injector/Injector.csproj.user b/Injector/Injector/Injector.csproj.user new file mode 100644 index 0000000..44862ff --- /dev/null +++ b/Injector/Injector/Injector.csproj.user @@ -0,0 +1,6 @@ + + + + /firmware=C:\Users\Brandon\Documents\GitHub\PS2251-03\BINs\FW03FF01V10353M.BIN /output=free.txt /action=FindFreeBlock + + \ No newline at end of file diff --git a/Injector/Injector/Properties/AssemblyInfo.cs b/Injector/Injector/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..34d8819 --- /dev/null +++ b/Injector/Injector/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DoPatch")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Toshiba")] +[assembly: AssemblyProduct("DoPatch")] +[assembly: AssemblyCopyright("Copyright © Toshiba 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("16a14751-01cb-4cb0-a3d1-7835d24f4711")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Injector/Injector/Startup.cs b/Injector/Injector/Startup.cs new file mode 100644 index 0000000..83165a3 --- /dev/null +++ b/Injector/Injector/Startup.cs @@ -0,0 +1,559 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace Injector +{ + class Startup + { + private static string _firmwareImage; + private static string _outputFile; + private static FirmwareSection _section = FirmwareSection.None; + private static Dictionary _codeFiles; + private static Dictionary _rstFiles; + + internal enum Action + { + None, + GenerateHFile, + FindFreeBlock, + ApplyPatches + } + + internal enum ExitCode + { + Success = 0, + Failure = 1 + } + + static void Main(string[] args) + { + try + { + _codeFiles = new Dictionary(); + _rstFiles = new Dictionary(); + + //Assume success to start with + Environment.ExitCode = (int)ExitCode.Success; + + var action = Action.None; + + //Parse command line arguments + foreach (var arg in args) + { + var parts = arg.TrimStart(new char[] { '/' }).Split(new char[] { '=' }, + StringSplitOptions.RemoveEmptyEntries); + switch (parts[0].ToLower()) + { + case "action": + { + action = (Action)Enum.Parse(typeof(Action), parts[1]); + Console.WriteLine("Action: " + action.ToString()); + break; + } + case "section": + { + _section = (FirmwareSection)Enum.Parse(typeof(FirmwareSection), parts[1]); + Console.WriteLine("Section: " + _section.ToString()); + break; + } + case "firmware": + { + _firmwareImage = parts[1]; + Console.WriteLine("Firmware image: " + _firmwareImage); + _CheckFirmwareImage(); + break; + } + case "output": + { + _outputFile = parts[1]; + Console.WriteLine("Output file: " + _outputFile); + break; + } + default: + { + _ParseFileNames(ref _codeFiles, "code", parts[0], parts[1]); + _ParseFileNames(ref _rstFiles, "rst", parts[0], parts[1]); + break; + } + } + } + + //Firmware image file name is always required + if (string.IsNullOrEmpty(_firmwareImage)) + { + throw new ArgumentException("No/Invalid firmware image file name specified"); + } + + switch (action) + { + case Action.GenerateHFile: + { + if (string.IsNullOrEmpty(_outputFile)) + { + throw new ArgumentException("No/Invalid output file name specified"); + } + + Console.WriteLine("Generating .h file..."); + + _GenerateHFile(); + break; + } + case Action.ApplyPatches: + { + //Check required arguments for this action + + if (string.IsNullOrEmpty(_outputFile)) + { + throw new ArgumentException("No/Invalid output file name specified"); + } + + if (_codeFiles.Count == 0) + { + throw new ArgumentException("No code file name(s) specified"); + } + + if (_rstFiles.Count == 0) + { + throw new ArgumentException("No/Invalid RST file name specified"); + } + + Console.WriteLine("Applying patches..."); + _ApplyPatches(); + break; + } + case Action.FindFreeBlock: + { + //Check required arguments for this action + if (_section == FirmwareSection.None) + { + throw new ArgumentException("No/Invalid section specified"); + } + + Console.WriteLine("Retriving free space..."); + _GetFreeSpaceToFile(); + break; + } + default: + throw new ArgumentException("No/Invalid action specified"); + } + + Console.WriteLine("Done."); + } + catch (Exception ex) + { + //Uh-oh... + Environment.ExitCode = (int)ExitCode.Failure; + + var asm = System.Reflection.Assembly.GetExecutingAssembly(); + var asmName = asm.GetName(); + Console.WriteLine(asmName.Name + " v" + asmName.Version.ToString(3)); + Console.WriteLine("Actions:"); + Console.WriteLine("\tGenerateHFile\tGenerates C .h file of common XRAM & function equates."); + Console.WriteLine("\tFindFreeBlock\tWrites amount of free space for a section to file."); + Console.WriteLine("\tApplyPatches\tApplies available patches from code into firmware image."); + Console.WriteLine(); + Console.WriteLine("FATAL: " + ex.ToString()); + } + } + + private static void _CheckFirmwareImage() + { + var md5 = new MD5CryptoServiceProvider(); + var verified = new List(); + verified.Add("4C4C0001EC83102C4627D271FF8362A2"); + + var hash = BitConverter.ToString(md5.ComputeHash(File.ReadAllBytes(_firmwareImage))) + .Replace("-", string.Empty); + if (!verified.Contains(hash)) + { + Console.WriteLine("WARNING! This firmware version has not been " + + "verified to work with these patches."); + } + } + + private static void _ParseFileNames(ref Dictionary files, + string suffix, string name, string value) + { + if (name.ToLower().EndsWith(suffix)) + { + var section = FirmwareSection.Base; + int s; + + if (int.TryParse(name.Substring(0, name.Length - suffix.Length), out s)) + { + section = (FirmwareSection)s; + } + + files.Add(section, value); + Console.WriteLine(suffix + " " + section.ToString() + " file: " + value); + } + } + + private static Dictionary _GetAddressMap(string fileName) + { + //Read in RST file and its label<->address map + var addressMap = new Dictionary(); + var ret = new Dictionary(); + var rst = new StreamReader(fileName, ASCIIEncoding.ASCII); + + while (true) + { + var line = rst.ReadLine(); + if (line == null) + { + break; + } + + if (line.EndsWith(":")) + { + var parts = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + var label = parts[parts.Length - 1].TrimEnd(':'); + var address = parts[0]; + + if (label.StartsWith("_")) + { + ret.Add(label, Convert.ToInt32(address, 16)); + } + } + } + + rst.Close(); + + return ret; + } + + private static void _GenerateHFile() + { + var stream = new StreamWriter(_outputFile); + + //Read in firmware image + var image = new FirmwareImage(_firmwareImage); + image.Open(); + + var pattern = new byte?[] { 0x90, 0xF0, 0xB8, 0xE0, //mov DPTR, #0xF0B8 \ movx a, @DPTR + 0x90, null, null, 0xF0, //mov DPTR, #0x???? \ movx @DPTR, a + 0x90, 0xF0, 0xB9, 0xE0 }; //mov DPTR, #0xF0B9 \ movx a, @DPTR \ movx DPTR, #0x???? + FirmwareSection section; + int address; + if (image.FindPattern(pattern, out section, out address)) + { + var a = image.GetSection(section)[address + 5] << 8; + a |= image.GetSection(section)[address + 6]; + + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", a.ToString("X04"), "bmRequestType")); + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", (a + 1).ToString("X04"), "bRequest")); + } + + pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx a, @DPTR + 0xB4, 0x28 }; //cjne A, #0x28, ???? + if (image.FindPattern(pattern, out section, out address)) + { + var a = image.GetSection(section)[address + 1] << 8; + a |= image.GetSection(section)[address + 2]; + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[16];", a.ToString("X04"), "scsi_cdb")); + + stream.WriteLine(string.Format("#define {0} 0x{1}", "DEFAULT_READ_SECTOR_HANDLER", (address + 7).ToString("X04"))); + pattern = new byte?[] { 0x90, (byte)((a >> 8) & 0xFF), (byte)(a & 0xFF), //mov DPTR, #scsi_tag + 0xE0, 0x12 }; //mvox A, @DPTR \ lcall 0x???? + if (image.FindPattern(pattern, address, out section, out address)) + { + stream.WriteLine(string.Format("#define {0} 0x{1}", "DEFAULT_CDB_HANDLER", address.ToString("X04"))); + } + } + + pattern = new byte?[] { 0x90, 0xF2, 0x1C, //mov DPTR, #0xF21C + 0x74, 0x55, 0xF0, //mov A, #0x55 \ movx @DPTR, A + 0x74, 0x53, 0xF0, //mov A, #0x53 \ movx @DPTR, A + 0x74, 0x42, 0xF0, //mov A, #0x42 \ movx @DPTR, A + 0x74, 0x53, 0xF0, //mov A, #0x53 \ movx @DPTR, A + 0x90 }; //mov DPTR, #0x???? + if (image.FindPattern(pattern, out section, out address)) + { + var a = image.GetSection(section)[address + pattern.Length] << 8; + a |= image.GetSection(section)[address + pattern.Length + 1]; + + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[4];", (a - 3).ToString("X04"), "scsi_tag")); + } + + pattern = new byte?[] { 0xC0, 0xE0, 0xC0, 0x83, 0xC0, 0x82, //push ACC \ push DPH \ push DPL + 0x90, 0xF0, 0x20, 0xE0, //mov DPTR, #0xF020 \ movx A, @DPTR + 0x30, 0xE1, null, //jnb ACC.1, ???? + 0x12, null, null, 0x90 }; //lcall ???? \ mov DPTR, #0x???? + if (image.FindPattern(pattern, out section, out address)) + { + var a = image.GetSection(section)[address + 17] << 8; + a |= image.GetSection(section)[address + 18]; + + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1};", a.ToString("X04"), "FW_EPIRQ")); + } + + stream.WriteLine(string.Format("__xdata __at 0x{0} BYTE {1}[1024];", "B000", "EPBUF")); + + stream.Close(); + } + + private static void _GetFreeSpaceToFile() + { + //Read in firmware image + var image = new FirmwareImage(_firmwareImage); + image.Open(); + + File.WriteAllText(_outputFile, "0x" + image.FindLastFreeChunk(_section).ToString("X04")); + } + + private static void _ApplyPatches() + { + //Read in firmware image + var image = new FirmwareImage(_firmwareImage); + image.Open(); + + //Read in the RST files + var maps = new Dictionary>(); + foreach (var file in _rstFiles) + { + maps.Add(file.Key, _GetAddressMap(file.Value)); + } + + //Find how much free space is left on each page + var emptyStart = new Dictionary(); + for (FirmwareSection i = FirmwareSection.Base; i < FirmwareSection.SectionF; i++) + { + emptyStart.Add(i, image.FindLastFreeChunk(i)); + } + + //Embed our code files into the firmware image + foreach (var file in _codeFiles) + { + var code = File.ReadAllBytes(file.Value); + Array.Copy(code, 0, image.GetSection(file.Key), emptyStart[file.Key], code.Length); + emptyStart[file.Key] += code.Length; + } + + //Find the off-page call stubs + var stubs = new Dictionary(); + int saddr = 0; + var spattern = new byte?[] { 0xC0, 0x5B, 0x74, 0x08, //push RAM_5B \ mov A, #8 + 0xC0, 0xE0, 0xC0, 0x82, 0xC0, 0x83, //push ACC \ push DPL \ push DPH + 0x75, 0x5B }; //mov RAM_5B, #0x?? + FirmwareSection fs; + for (FirmwareSection i = FirmwareSection.Section0; i <= FirmwareSection.SectionF; i++) + { + if (image.FindPattern(spattern, saddr, out fs, out saddr)) + { + stubs.Add(i, saddr); + saddr += spattern.Length; //move ahead so we can find the next stub + } + } + + //Hook into control request handling + foreach (var map in maps) + { + if (map.Value.ContainsKey("_HandleControlRequest")) + { + var address = map.Value["_HandleControlRequest"]; + var pattern = new byte?[] { 0x12, null, null, //lcall #0x???? + 0x90, 0xFE, 0x82, 0xE0, //mov DPTR, #0xFE82 \ movx A, @DPTR + 0x54, 0xEF, 0xF0 }; //anl A, #0xEF \ movx @DPTR, A + FirmwareSection s; + int a; + if (image.FindPattern(pattern, out s, out a)) + { + a = (image.GetSection(s)[a + 1] << 8) | image.GetSection(s)[a + 2]; + + image.GetSection(s)[a + 1] = (byte)((address >> 8) & 0xFF); + image.GetSection(s)[a + 2] = (byte)(address & 0xFF); + if (map.Key != FirmwareSection.Base) + { + image.GetSection(s)[a + 4] = (byte)((stubs[map.Key] >> 8) & 0xFF); + image.GetSection(s)[a + 5] = (byte)(stubs[map.Key] & 0xFF); + } + } + break; + } + } + + //Replace the EP interrupt vector, handling all incoming and outgoing non-control data + foreach (var map in maps) + { + //This part must be on the base page + if (map.Value.ContainsKey("_EndpointInterrupt")) + { + var address = map.Value["_EndpointInterrupt"]; + var s = image.GetSection(FirmwareSection.Base); + s[0x0014] = (byte)((address >> 8) & 0xFF); + s[0x0015] = (byte)(address & 0xFF); + } + + if (map.Value.ContainsKey("_HandleEndpointInterrupt")) + { + //Find the base page location to patch + var pattern = new byte?[] { 0x30, 0xE1, null, //jnb ACC.1, #0x???? + 0x12, null, null, //lcall #0x???? + 0x90, 0xFE, 0x82, 0xE0, //mov DPTR, #0xFE82 \ movx A, @DPTR + 0x54, 0xEF, 0xF0 }; //anl A, #0xEF \ movx @DPTR, A + FirmwareSection ps; + int pa; + if (image.FindPattern(pattern, out ps, out pa)) + { + //Create off-page stub for this if necessary + var address = map.Value["_HandleEndpointInterrupt"]; + var stubAddress = address; + if (map.Key != FirmwareSection.Base) + { + stubAddress = emptyStart[FirmwareSection.Base]; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); + } + + //Apply the patch + var s = image.GetSection(ps); + s[pa + 0] = 0x60; + s[pa + 1] = 0x0B; + s[pa + 2] = 0x00; + s[pa + 4] = (byte)((stubAddress >> 8) & 0xFF); + s[pa + 5] = (byte)(stubAddress & 0xFF); + for (int i = 0; i < 7; i++) + { + s[pa + 6 + i] = 0x00; + } + } + } + } + + //Apply CDB-handling code + foreach (var map in maps) + { + if (map.Value.ContainsKey("_HandleCDB")) + { + var pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx a, @DPTR + 0xB4, 0x28 }; //cjne A, #0x28, ???? + FirmwareSection ps; + int pa; + if (image.FindPattern(pattern, out ps, out pa)) + { + //Create off-page stub for this if necessary + var address = map.Value["_HandleCDB"]; + var stubAddress = address; + if (map.Key != FirmwareSection.Base) + { + stubAddress = emptyStart[FirmwareSection.Base]; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); + } + + //Apply the patch + var s = image.GetSection(FirmwareSection.Base); + s[pa + 0] = 0x02; + s[pa + 1] = (byte)((stubAddress >> 8) & 0xFF); + s[pa + 2] = (byte)(stubAddress & 0xFF); + } + } + } + + //Add our own code to the infinite loop + foreach (var map in maps) + { + if (map.Value.ContainsKey("_LoopDo")) + { + var pattern = new byte?[] { 0x90, null, null, 0xE0, //mov DPTR, #0x???? \ movx A, @DPTR + 0xB4, 0x01, null, //cjne A, #1, #0x???? + 0x90, 0xF0, 0x79 }; //mov DPTR, #0xF079 + FirmwareSection ps; + int pa; + if (image.FindPattern(pattern, out ps, out pa)) + { + //Create off-page stub for this if necessary + var address = map.Value["_LoopDo"]; + var stubAddress = address; + if (map.Key != FirmwareSection.Base) + { + stubAddress = emptyStart[FirmwareSection.Base]; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); + } + + var s = image.GetSection(ps); + var loopDoStart = emptyStart[FirmwareSection.Base]; + s[emptyStart[FirmwareSection.Base]++] = 0x12; + s[emptyStart[FirmwareSection.Base]++] = (byte)((stubAddress >> 8) & 0xFF); + s[emptyStart[FirmwareSection.Base]++] = (byte)(stubAddress & 0xFF); + s[emptyStart[FirmwareSection.Base]++] = 0x90; + s[emptyStart[FirmwareSection.Base]++] = image.GetSection(ps)[pa + 1]; + s[emptyStart[FirmwareSection.Base]++] = image.GetSection(ps)[pa + 2]; + s[emptyStart[FirmwareSection.Base]++] = 0x22; + s[pa + 0] = 0x12; + s[pa + 1] = (byte)((loopDoStart >> 8) & 0xFF); + s[pa + 2] = (byte)(loopDoStart & 0xFF); + } + } + } + + //Apply password patch code + foreach (var map in maps) + { + if (map.Value.ContainsKey("_PasswordReceived")) + { + var pattern = new byte?[] { 0x90, 0xF2, 0x4C, 0xF0, 0xA3, //mov DPTR, #0xF24C \ movx @DPTR, A \ inc DPTR + 0xC0, 0x83, 0xC0, 0x82, 0x12, //push DPH \ push DPL + null, null, 0xD0, 0x82, 0xD0, 0x83, 0xF0, //lcall #0x???? \ pop DPL \ pop DPH \ movx @DPTR, A + 0x90, 0xF2, 0x53, 0x74, 0x80, 0xF0, //mov DPTR, #0xF253 \ mov A, #0x80 \ movx @DPTR, A + 0x90, 0xF2, 0x53, 0xE0, //mov DPTR, #0xF253 \ movx A, @DPTR + 0x30, 0xE7, null, //jnb ACC.7, #0x???? + 0x12, null, null, 0x40, null, //lcall #0x???? \ jc #0x???? + 0x12, null, null, 0x7F, 0x00, 0x22 }; //lcall #0x???? \ mov R7, #0 \ ret + FirmwareSection ps; + int pa; + if (image.FindPattern(pattern, out ps, out pa)) + { + //Create off-page stub for this if necessary + var address = map.Value["_PasswordReceived"]; + var stubAddress = address; + if (map.Key != FirmwareSection.Base) + { + stubAddress = emptyStart[FirmwareSection.Base]; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x90; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((address >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(address & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = 0x02; + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)((stubs[map.Key] >> 8) & 0xFF); + image.GetSection(FirmwareSection.Base)[emptyStart[FirmwareSection.Base]++] = (byte)(stubs[map.Key] & 0xFF); + } + + //Apply the patch + pa += 0x24; + var passRecvdStart = emptyStart[ps] + (ps == FirmwareSection.Base ? 0x0000 : 0x5000); + image.GetSection(ps)[emptyStart[ps]++] = 0x12; + image.GetSection(ps)[emptyStart[ps]++] = image.GetSection(ps)[pa + 0]; + image.GetSection(ps)[emptyStart[ps]++] = image.GetSection(ps)[pa + 1]; + image.GetSection(ps)[emptyStart[ps]++] = 0x02; + image.GetSection(ps)[emptyStart[ps]++] = (byte)((stubAddress >> 8) & 0xFF); + image.GetSection(ps)[emptyStart[ps]++] = (byte)(stubAddress & 0xFF); + image.GetSection(ps)[pa + 0] = (byte)((passRecvdStart >> 8) & 0xFF); + image.GetSection(ps)[pa + 1] = (byte)(passRecvdStart & 0xFF); + } + } + } + + //Write the resulting file out + image.Save(_outputFile); + } + } +} diff --git a/docs/PinsToShortUponPlugInForBootMode.jpg b/docs/PinsToShortUponPlugInForBootMode.jpg new file mode 100644 index 0000000..ebb10c6 Binary files /dev/null and b/docs/PinsToShortUponPlugInForBootMode.jpg differ diff --git a/firmware/build.bat b/firmware/build.bat new file mode 100644 index 0000000..b42cc93 --- /dev/null +++ b/firmware/build.bat @@ -0,0 +1,41 @@ +@ECHO OFF + +REM Set things up and create bin directory if necessary. +SETLOCAL ENABLEDELAYEDEXPANSION +SET BUILD_FILES= +IF NOT EXIST bin\NUL MKDIR bin + +REM Build each file in the list. +FOR %%A IN ( +main +timers +usb +control +scsi +) DO ( +ECHO *** Building %%A.c... +sdcc --model-small -mmcs51 -pdefcpu -c -obin\%%A.rel %%A.c +IF ERRORLEVEL 1 GOTO ERRORS +SET "BUILD_FILES=!BUILD_FILES! bin\%%A.rel" +) + +REM Build Intel Hex and BIN versions of combined file. +sdcc --xram-loc 0x6000 -o bin\output.hex %BUILD_FILES% +IF ERRORLEVEL 1 GOTO ERRORS +makebin -p bin\output.hex bin\output.bin + +REM Create firmware and burner images from templates. +copy /y ..\templates\FWdummy.bin bin\fw.bin > NUL +copy /y ..\templates\BNdummy.bin bin\bn.bin > NUL +..\tools\sfk partcopy bin\output.bin -fromto 0 -1 bin\fw.bin 512 -yes > NUL +..\tools\sfk partcopy bin\output.bin -fromto 0 -1 bin\bn.bin 512 -yes > NUL + +GOTO END + +:ERRORS +ECHO *** There were errors^^! *** + +:END +ECHO *** Done. + +ENDLOCAL diff --git a/firmware/control.c b/firmware/control.c new file mode 100644 index 0000000..755e710 --- /dev/null +++ b/firmware/control.c @@ -0,0 +1,184 @@ +#include "defs.h" +#include "usb.h" +#include "timers.h" + +static const BYTE deviceDescriptor[] = { 0x12, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, + 0xFE, 0x13, 0x01, 0x52, 0x10, 0x01, 0x00, 0x00, 0x00, 0x01 }; +static const BYTE configDescriptor[] = { 0x09, 0x02, sizeof(configDescriptor) & 0xFF, sizeof(configDescriptor) >> 8, 0x02, 0x01, 0x00, 0x80, 0x4B, + 0x09, 0x04, 0x00, 0x00, 0x03, 0x08, 0x06, 0x50, 0x00, + 0x07, 0x05, 0x81, 0x02, 0x40, 0x00, 0x00, + 0x07, 0x05, 0x02, 0x02, 0x40, 0x00, 0x00, + 0x07, 0x05, 0x83, 0x03, 0x08, 0x00, 0x00, + 0x09, 0x04, 0x01, 0x00, 0x02, 0x03, 0x01, 0x01, 0x00, + 0x09, 0x21, 0x01, 0x01, 0x00, 0x01, 0x22, + sizeof(HIDreportDescriptor) & 0xFF, + sizeof(HIDreportDescriptor) >> 8, + 0x07, 0x05, 0x83, 0x03, 0x08, 0x00, 0x01, + //This is a dummy endpoint to make the descriptor != 0x40, because the controller is stupid. + 0x07, 0x05, 0x04, 0x03, 0x08, 0x00, 0x01 }; +static const BYTE HIDreportDescriptor[] = { 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, + 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, + 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, + 0x95, 0x05, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x05, + 0x91, 0x02, 0x95, 0x01, 0x75, 0x03, 0x91, 0x01, 0x95, 0x06, + 0x75, 0x08, 0x15, 0x00, 0x25, 0x65, 0x05, 0x07, 0x19, 0x00, + 0x29, 0x65, 0x81, 0x00, 0xC0 }; +static const BYTE deviceQualifierDescriptor[] = { 0x0A, 0x06, 0x00, 0x02, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00 }; + +void EP0ACK() +{ + EP0CS = bmEP0ACK; +} + +static BYTE SetAddress() +{ + BYTE ret = FALSE; + + if (wValue < 0x7F) + { + EP0ACK(); + ret = TRUE; + } + + return ret; +} + +static BYTE GetDescriptor() +{ + BYTE type = (wValue >> 8) & 0xFF; + BYTE i, total; + BYTE ret = FALSE; + + switch (type) + { + case 0x01: + { + for (i = 0; i < 0x12; i++) + { + EP0.fifo = deviceDescriptor[i]; + } + + SendControlResponse(wLength < 0x12 ? wLength : 0x12); + ret = TRUE; + + break; + } + case 0x02: + { + total = wLength < sizeof(configDescriptor) ? wLength : sizeof(configDescriptor); + for (i = 0; i < total; i++) + { + EP0.fifo = configDescriptor[i]; + } + + SendControlResponse(total); + ret = TRUE; + + break; + } + case 0x06: + { + for (i = 0; i < sizeof(deviceQualifierDescriptor); i++) + { + EP0.fifo = deviceQualifierDescriptor[i]; + } + + SendControlResponse(wLength < sizeof(deviceQualifierDescriptor) ? wLength : sizeof(deviceQualifierDescriptor)); + ret = TRUE; + + break; + } + case 0x22: + { + for (i = 0; i < sizeof(HIDreportDescriptor); i++) + { + EP0.fifo = HIDreportDescriptor[i]; + } + + SendControlResponse(wLength < sizeof(HIDreportDescriptor) ? wLength : sizeof(HIDreportDescriptor)); + ret = TRUE; + + break; + } + default: + { + break; + } + } + + return ret; +} + +static BYTE SetConfiguration() +{ + BYTE ret = FALSE; + + if (wValue <= 1) + { + EP0ACK(); + ret = TRUE; + } + + return ret; +} + +BYTE HandleStandardRequest() +{ + switch(bRequest) + { + case 0x05: + { + return SetAddress(); + } + case 0x06: + { + return GetDescriptor(); + } + case 0x09: + { + return SetConfiguration(); + } + default: + { + return FALSE; + } + } +} + +static BYTE GetMaxLUN() +{ + EP0.fifo = 0x00; + SendControlResponse(wLength < 0x01 ? wLength : 0x01); + + return TRUE; +} + +BYTE HandleClassRequest() +{ + switch(bRequest) + { + case 0x09: + { + EP0CS = 0x05; + return TRUE; + } + case 0x0A: + { + EP0ACK(); + return TRUE; + } + case 0xFE: + { + return GetMaxLUN(); + } + default: + { + return FALSE; + } + } +} + +BYTE HandleVendorRequest() +{ + return FALSE; +} diff --git a/firmware/defs.h b/firmware/defs.h new file mode 100644 index 0000000..0568382 --- /dev/null +++ b/firmware/defs.h @@ -0,0 +1,202 @@ +#ifndef DEFS_H +#define DEFS_H + +#define MSB(word) (BYTE)(((WORD)(word) >> 8) & 0xff) +#define LSB(word) (BYTE)((WORD)(word) & 0xff) + +#define XVAL(addr) (*( __xdata volatile unsigned char *)(addr)) +#define IVAL(addr) (*( __idata volatile unsigned char *)(addr)) + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +#define TRUE 1 +#define FALSE 0 + +#define BANK0_PA 0x008000UL +#define BANK1_VA 0x4000U +#define BANK1_PA 0x00C000UL +#define BANK2_VA 0x6000U +#define BANK2_PA 0x00E000UL + +#define usb_buffer_PA 0x008000UL +#define usb_buffer_VA 0x0000U + +#define USB_VECT 0 +#define TMR0_VECT 1 +#define EP_VECT 2 +#define TMR1_VECT 3 +#define COM0_VECT 4 + +#define bmAttach 0x80 +#define bmSpeed 7 +#define bmSuperSpeed 4 +#define bmHighSpeed 0 +#define bmFullSpeed 1 +#define bmSpeedChange 0x80 +#define bmEP2IRQ 2 +#define bmEP4IRQ 8 +#define bmEP0ACK 1 +#define bmEP0NAK 2 +#define bmEP0IN 4 +#define bmEP0STALL 8 +#define bmSUDAV 0x80 +#define bmSTALL 2 + +#define bmNandReady 1 + +#define bmNandDma0 0 +#define bmNandDma1 0x80 +#define bmNandDmaRead 0 +#define bmNandDmaWrite 0x40 + +#define bmDmaCmd 7 +#define bmDmaCopy 2 +#define bmDmaFill 4 +#define bmDmaWidth8 0 +#define bmDmaWidth16 0x40 +#define bmDmaWidth32 0x80 + +#define bmPRAM 1 + +__sfr __at (0x80) P0 ; +__sfr __at (0x90) P1 ; +__sfr __at (0xA0) P2 ; +__sfr __at (0xB0) P3 ; +__sfr __at (0xD0) PSW ; +__sfr __at (0xE0) ACC ; +__sfr __at (0xF0) B ; +__sfr __at (0x81) SP ; +__sfr __at (0x82) DPL ; +__sfr __at (0x83) DPH ; +__sfr __at (0x87) PCON; +__sfr __at (0x88) TCON; +__sfr __at (0x89) TMOD; +__sfr __at (0x8A) TL0 ; +__sfr __at (0x8B) TL1 ; +__sfr __at (0x8C) TH0 ; +__sfr __at (0x8D) TH1 ; +__sfr __at (0xA8) IE ; +__sfr __at (0xB8) IP ; +__sfr __at (0x98) SCON; +__sfr __at (0x99) SBUF; + +/* BIT Register */ +/* PSW */ +__sbit __at (0xD7) CY ; +__sbit __at (0xD6) AC ; +__sbit __at (0xD5) F0 ; +__sbit __at (0xD4) RS1 ; +__sbit __at (0xD3) RS0 ; +__sbit __at (0xD2) OV ; +__sbit __at (0xD0) P ; + +/* TCON */ +__sbit __at (0x8F) TF1 ; +__sbit __at (0x8E) TR1 ; +__sbit __at (0x8D) TF0 ; +__sbit __at (0x8C) TR0 ; +__sbit __at (0x8B) IE1 ; +__sbit __at (0x8A) IT1 ; +__sbit __at (0x89) IE0 ; +__sbit __at (0x88) IT0 ; + +/* IE */ +__sbit __at (0xAF) EA ; +__sbit __at (0xAC) ES ; +__sbit __at (0xAB) ET1 ; +__sbit __at (0xAA) EX1 ; +__sbit __at (0xA9) ET0 ; +__sbit __at (0xA8) EX0 ; + +/* IP */ +__sbit __at (0xBC) PS ; +__sbit __at (0xBB) PT1 ; +__sbit __at (0xBA) PX1 ; +__sbit __at (0xB9) PT0 ; +__sbit __at (0xB8) PX0 ; + +/* P3 */ +__sbit __at (0xB7) RD ; +__sbit __at (0xB6) WR ; +__sbit __at (0xB5) T1 ; +__sbit __at (0xB4) T0 ; +__sbit __at (0xB3) INT1; +__sbit __at (0xB2) INT0; +__sbit __at (0xB1) TXD ; +__sbit __at (0xB0) RXD ; + +/* SCON */ +__sbit __at (0x9F) SM0 ; +__sbit __at (0x9E) SM1 ; +__sbit __at (0x9D) SM2 ; +__sbit __at (0x9C) REN ; +__sbit __at (0x9B) TB8 ; +__sbit __at (0x9A) RB8 ; +__sbit __at (0x99) TI ; +__sbit __at (0x98) RI ; + +__xdata __at 0xF000 volatile BYTE REGBANK; +__xdata __at 0xF008 volatile BYTE USBCTL; +__xdata __at 0xF009 volatile BYTE USBSTAT; +__xdata __at 0xF027 volatile BYTE USBIRQ; +__xdata __at 0xF020 volatile BYTE EPIRQ; +__xdata __at 0xF030 volatile BYTE EPIE; +__xdata __at 0xF048 volatile BYTE EP0CS; +__xdata __at 0xF0B8 volatile BYTE SETUPDAT[8]; + +typedef struct +{ + BYTE r0, r1, r2, r3, r4; + BYTE ptr_l, ptr_m, ptr_h; + BYTE r8, r9; + BYTE offset; + BYTE rB; + BYTE len_l, len_m, len_h; + BYTE rF, r10, r11, r12; + BYTE cs; + BYTE r14, r15, r16, r17, r18, r19; + BYTE fifo_count; + BYTE r1B; + BYTE fifo; +} EPREGS; + +__xdata __at 0xF1C0 volatile EPREGS EP0; +__xdata __at 0xF200 volatile EPREGS EP1; +__xdata __at 0xF240 volatile EPREGS EP2; +__xdata __at 0xF280 volatile EPREGS EP3; +__xdata __at 0xF2C0 volatile EPREGS EP4; + +__xdata __at 0xF608 volatile BYTE NANDCSOUT; +__xdata __at 0xF618 volatile BYTE NANDCSDIR; + +__xdata __at 0xF900 volatile BYTE DMASRCL; +__xdata __at 0xF901 volatile BYTE DMASRCM; +__xdata __at 0xF902 volatile BYTE DMASRCH; +__xdata __at 0xF904 volatile BYTE DMADSTL; +__xdata __at 0xF905 volatile BYTE DMADSTM; +__xdata __at 0xF906 volatile BYTE DMADSTH; +__xdata __at 0xF908 volatile BYTE DMASIZEL; +__xdata __at 0xF909 volatile BYTE DMASIZEM; +__xdata __at 0xF90A volatile BYTE DMASIZEH; +__xdata __at 0xF90C volatile BYTE DMAFILL0; +__xdata __at 0xF90D volatile BYTE DMAFILL1; +__xdata __at 0xF90E volatile BYTE DMAFILL2; +__xdata __at 0xF90F volatile BYTE DMAFILL3; +__xdata __at 0xF930 volatile BYTE DMACMD; + +__xdata __at 0xFA14 volatile BYTE GPIO0DIR; +__xdata __at 0xFA15 volatile BYTE GPIO0OUT; +__xdata __at 0xFA38 volatile BYTE WARMSTATUS; + +__xdata __at 0xFA40 volatile BYTE BANK0PAL; +__xdata __at 0xFA41 volatile BYTE BANK0PAH; +__xdata __at 0xFA42 volatile BYTE BANK1VA; +__xdata __at 0xFA43 volatile BYTE BANK1PAL; +__xdata __at 0xFA44 volatile BYTE BANK1PAH; +__xdata __at 0xFA45 volatile BYTE BANK2VA; +__xdata __at 0xFA46 volatile BYTE BANK2PAL; +__xdata __at 0xFA47 volatile BYTE BANK2PAH; +__xdata __at 0xFA48 volatile BYTE PRAMCTL; //bit 0 set means run from PRAM + +#endif diff --git a/firmware/main.c b/firmware/main.c new file mode 100644 index 0000000..5ae362e --- /dev/null +++ b/firmware/main.c @@ -0,0 +1,170 @@ +#include "defs.h" +#include "timers.h" +#include "usb.h" + +extern void usb_isr(void) __interrupt USB_VECT; +extern void ep_isr(void) __interrupt EP_VECT; +extern void tmr0isr(void) __interrupt TMR0_VECT; +extern void tmr1isr(void) __interrupt TMR1_VECT; + +#define KEY_DELAY 8192 +#define KEY_BUFFER_SIZE 0x2000 +static const BYTE keyData[KEY_BUFFER_SIZE] = { /*0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, + 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xC3, + 0x15, 0x08, 0x00, 0xFF, 0x00, 0xF5, 0x11, 0x00, 0x12, 0x00, 0x17, 0x00, 0x08, 0x00, 0x13, + 0x00, 0x04, 0x00, 0x07, 0x00, 0x00, 0xFF, 0x00, 0xF5, 0x28, 0x00, 0x00, 0xFF, 0x00, 0xFF, + 0x00, 0xF0, 0x0B, 0x02, 0x08, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x12, 0x00, 0x2C, 0x00, 0x1A, + 0x02, 0x12, 0x00, 0x15, 0x00, 0x0F, 0x00, 0x07, 0x00, 0x1E, 0x02, 0x1E, 0x02, 0x1E, 0x02, + 0x28, 0x00*/ 0x12, 0x34, 0x56, 0x78 }; +int key_index = 0; +volatile BYTE send_keys_enabled = 0; +DWORD wait_counter = KEY_DELAY; +DWORD wait_tick; + +void InitHardware() +{ + //Set up RAM mapping just beyond our own code + BANK0PAL = BANK0_PA>>9; + BANK0PAH = BANK0_PA>>17; + BANK1VA = BANK1_VA>>8; + BANK1PAL = BANK1_PA>>9; + BANK1PAH = BANK1_PA>>17; + BANK2VA = BANK2_VA>>8; + BANK2PAL = BANK2_PA>>9; + BANK2PAH = BANK2_PA>>17; + + XVAL(0xF809) = 7; + XVAL(0xF80A) = 0x1F; + XVAL(0xF810) = 0x60; + XVAL(0xF811) = 0; + XVAL(0xF08F) = 0; + + XVAL(0xFA6F) = 0x1F; + XVAL(0xFA60) = 2; + XVAL(0xFA61) = 0; + XVAL(0xFA64) = 0; + XVAL(0xFA65) = 0; + XVAL(0xFA66) = 0; + XVAL(0xFA67) = 0; + XVAL(0xFA62) = 0x0F; + XVAL(0xFA6F) = 0x1F; + + GPIO0DIR &= 0xFD; + GPIO0OUT |= 2; + + XVAL(0xFA21) = 7; + XVAL(0xFA21) &= 0xFB; + + XVAL(0xFA68) &= 0xF7; + XVAL(0xFA69) &= 0xF7; + XVAL(0xFA6A) &= 0xF7; + XVAL(0xFA6B) &= 0xF7; + + XVAL(0xFE00) = 0; + XVAL(0xFE00) = 0x80; + + XVAL(0xFA50) = 0x20; + + XVAL(0xFE01) = 0; + XVAL(0xFE02) = 0x45; + + TMOD = 0x11; + TH0 = 0xF0; + TL0 = 0x5F; + TH1 = 0xF0; + TL1 = 0x5F; + IP = 1; + TCON = 0x10; + SCON = 0; + IE = 0x80; +} + +void DoUSBRelatedInit() +{ + if (WARMSTATUS & 2) + { + return; + } + + REGBANK = 5; + XVAL(0xF210) = 0xFF; + XVAL(0xF211) = 2; + XVAL(0xF212) = 3; + XVAL(0xF213) = 0x24; + REGBANK = 0; + XVAL(0xFA6B) = 0xFF; + while((XVAL(0xF014) & 3)==0); +} + +void SendKey(BYTE code, BYTE modifiers) +{ + int i; + + EP3.cs = 0; + while (EP3.cs & 0x40); + + EP3.fifo = modifiers; + EP3.fifo = 0; + EP3.fifo = code; + for (i = 0; i < 5; i++) + { + EP3.fifo = 0; + } + + EP3.len_l = 8; + EP3.len_m = 0; + EP3.len_h = 0; + EP3.cs = 0x40; +} + +void main() +{ + InitHardware(); + DoUSBRelatedInit(); + InitUSB(); + InitTicks(); + InitLED(); + LEDBlink(); + + while (1) + { + HandleUSBEvents(); + + if (wait_tick++ >= KEY_DELAY) + { + if (wait_counter < KEY_DELAY) + { + wait_counter++; + } + } + + if (send_keys_enabled && wait_counter >= KEY_DELAY) + { + if (keyData[key_index]) + { + //Send this key, with some padding before, since something's wonky with endpoint 3 + SendKey(0x00, 0x00); + SendKey(0x00, 0x00); + SendKey(0x00, 0x00); + SendKey(0x00, 0x00); + SendKey(keyData[key_index], keyData[key_index + 1]); + SendKey(0x00, 0x00); + } + else + { + //Wait a while + wait_counter = 0; + wait_tick = 0; + } + + //Move to next key + key_index += 2; + + //Are we done? + if (key_index >= sizeof(keyData)) + { + send_keys_enabled = 0; + } + } + } +} diff --git a/firmware/scsi.c b/firmware/scsi.c new file mode 100644 index 0000000..7673c46 --- /dev/null +++ b/firmware/scsi.c @@ -0,0 +1,158 @@ +#include "defs.h" +#include "string.h" +#include "usb.h" + +#define PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +#define TEST_UNIT_READY 0x00 +#define INQUIRY 0x12 +#define READ_FORMAT_CAPACITIES 0x23 +#define MODE_SENSE 0x1A +#define REQUEST_SENSE 0x03 + +#define VENDOR_BOOT 0xBF +#define VENDOR_INFO 0x05 +#define CUSTOM_XPEEK 0x06 +#define CUSTOM_XPOKE 0x07 +#define CUSTOM_IPEEK 0x08 +#define CUSTOM_IPOKE 0x09 + +BYTE scsi_status; +DWORD scsi_data_residue; +DWORD scsi_transfer_size; +BYTE scsi_tag[4]; +BYTE scsi_dir_in; +BYTE scsi_lun; +BYTE scsi_cdb[16]; +BYTE scsi_cdb_size; + +BYTE HandleCDB() +{ + //Default to returning a bad status + scsi_status = 1; + + switch(scsi_cdb[0]) + { + case PREVENT_ALLOW_MEDIUM_REMOVAL: + { + scsi_status = 0; + return 1; + } + case TEST_UNIT_READY: + { + return 1; + } + case INQUIRY: + { + memset(usb_buffer, 0, 36); + usb_buffer[1] = 0x80; //removable media + usb_buffer[3] = 0x01; //because the UFI spec says so + usb_buffer[4] = 0x1F; //additional length + SendData1(36, 0); + scsi_status = 0; + return 1; + } + case READ_FORMAT_CAPACITIES: + { + memset(usb_buffer, 0, 12); + usb_buffer[3] = 0x08; //capacity list length + usb_buffer[6] = 0x10; //number of blocks (sectors) (dummy 2MB) + usb_buffer[8] = 0x03; + usb_buffer[10] = 0x02; //block length (512 bytes/sector) + SendData1(12, 0); + scsi_status = 0; + return 1; + } + case MODE_SENSE: + { + memset(usb_buffer, 0, 8); + usb_buffer[0] = 0x03; + usb_buffer[2] = 0x80; + SendData1(4, 0); + scsi_status = 0; + return 1; + } + case REQUEST_SENSE: + { + memset(usb_buffer, 0, 18); + usb_buffer[0] = 0x70; + usb_buffer[2] = 0x02; + usb_buffer[7] = 10; + usb_buffer[12] = 0x3A; + SendData1(18, 0); + scsi_status = 0; + return 1; + } + //Vendor-specific requests + case 0x06: + case 0xC6: + case 0xC7: + { + switch(scsi_cdb[1]) + { + case CUSTOM_XPEEK: + { + usb_buffer[0] = XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]); + SendData1(1, 0); + break; + } + case CUSTOM_XPOKE: + { + XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]) = scsi_cdb[4]; + SendData1(1, 0); + break; + } + case CUSTOM_IPEEK: + { + usb_buffer[0] = IVAL(scsi_cdb[2]); + SendData1(1, 0); + break; + } + case CUSTOM_IPOKE: + { + IVAL(scsi_cdb[2]) = scsi_cdb[3]; + SendData1(1, 0); + break; + } + case VENDOR_INFO: //get info + { + int i; + + memset(usb_buffer, 0x00, 0x210); + for (i = 0; i < 0x200; i++) + { + usb_buffer[i] = *((BYTE __xdata *)(0x5000 + i)); + } + + usb_buffer[0x200] = 'I'; + usb_buffer[0x201] = 'F'; + SendData1(0x210, 0); + scsi_status = 0; + return 1; + } + case VENDOR_BOOT: + { + //This transfers control to boot mode and will not return. + XVAL(0xFA14) = 0x07; + XVAL(0xF747) &= 0xEF; + XVAL(0xFA15) = 0x06; + XVAL(0xFA38) |= 0x01; + XVAL(0xF08F) = 0x00; + XVAL(0xFA68) &= 0xF7; + XVAL(0xFA6A) &= 0xF7; + XVAL(0xFA48) &= 0xFE; + break; + } + default: + { + //Not handling it, then + return 0; + } + } + } + default: + { + //Not handling it, then + return 0; + } + } +} diff --git a/firmware/test.bat b/firmware/test.bat new file mode 100644 index 0000000..f2f1278 --- /dev/null +++ b/firmware/test.bat @@ -0,0 +1,2 @@ +@ECHO OFF +..\tools\DriveCom /action=SendFirmware /drive=E /burner=..\BINs\BN03V104M.BIN /firmware=bin\fw.bin diff --git a/firmware/timers.c b/firmware/timers.c new file mode 100644 index 0000000..39036cb --- /dev/null +++ b/firmware/timers.c @@ -0,0 +1,116 @@ +#include "defs.h" +#include "timers.h" + +static BYTE tmr0count, led_ticks, led_timer, led_tick_threshold; +static BYTE tmr1count; +static WORD tmr1reload; + +void tmr1isr(void) __interrupt TMR1_VECT +{ + TR1 = 0; + TH1 = MSB(tmr1reload); + TL1 = LSB(tmr1reload); + tmr1count++; + TR1 = 1; +} + +void InitTicks() +{ + if (XVAL(0xFA60) == 0x0F) + { + tmr1reload = 0xF63C; + } + else + { + tmr1reload = 0-(2500/(XVAL(0xFA60)+2)); + } + + tmr1count = 0; + TR1 = 0; + ET1 = 1; + TMOD = TMOD & 0x0F | 0x10; +} + +BYTE GetTickCount(void) +{ + return tmr1count; +} + +void tmr0isr(void) __interrupt TMR0_VECT +{ + //approx. 10 times per second + TR0 = 0; + TL0 = 0xE6; + TH0 = 0x96; + TR0 = 1; + + if ((GPIO0OUT & 2) == 0) //turned off + { + return; + } + + tmr0count++; + led_ticks++; + if (led_ticks < led_tick_threshold) + { + return; + } + + led_ticks = 0; + if (led_timer >= 31) + { + GPIO0OUT = 1; + led_timer = 0; + return; + } + + if (led_timer >= 10) + { + GPIO0OUT = ~GPIO0OUT; + led_timer++; + return; + } + + if (led_timer == 0) + { + return; + } + + if (GPIO0OUT & 1) + { + GPIO0OUT &= 0xFE; + } + else + { + GPIO0OUT |= 1; + } +} + +void SetLEDThreshold(int threshold) +{ + led_tick_threshold = threshold; +} + +void InitLED(void) +{ + led_tick_threshold = 100; + tmr0count = 0; + GPIO0OUT = 3; + led_ticks = 0; + led_timer = 0; + EA = 1; + ET0 = 1; + TR0 = 1; +} + +void LEDBlink(void) +{ + GPIO0OUT = 2; + led_timer = 1; +} + +void LEDOff(void) +{ + GPIO0OUT = 3; + led_timer = 0; +} diff --git a/firmware/timers.h b/firmware/timers.h new file mode 100644 index 0000000..3b40859 --- /dev/null +++ b/firmware/timers.h @@ -0,0 +1,12 @@ +#ifndef _TIMERS_H_INCLUDED +#define _TIMERS_H_INCLUDED + +void InitLED(void); +void SetLEDThreshold(int threshold); +void LEDBlink(void); +void LEDOff(void); + +void InitTicks(); +BYTE GetTickCount(void); + +#endif diff --git a/firmware/usb.c b/firmware/usb.c new file mode 100644 index 0000000..0796caa --- /dev/null +++ b/firmware/usb.c @@ -0,0 +1,518 @@ +#include "defs.h" +#include "string.h" +#include "timers.h" + +__xdata __at usb_buffer_VA volatile BYTE usb_buffer[1024]; + +BYTE bmRequestType; +BYTE bRequest; +WORD wValue; +WORD wIndex; +WORD wLength; + +static __xdata BYTE usb_irq; +static __xdata BYTE UsbIntStsF080, UsbIntStsF082, UsbIntStsF086, UsbIntStsF087; + +BYTE usb_speed; +__xdata volatile BYTE usb_received_data_ready, usb_have_csw_ready; + +extern BYTE scsi_status; +extern DWORD scsi_data_residue; +extern DWORD scsi_transfer_size; +extern BYTE scsi_tag[4]; +extern BYTE scsi_dir_in; +extern BYTE scsi_cdb[16]; +extern BYTE scsi_lun; +extern BYTE scsi_cdb_size; +extern BYTE HandleCDB(void); +extern volatile BYTE send_keys_enabled; + +extern BYTE HandleStandardRequest(void); +extern BYTE HandleClassRequest(void); +extern BYTE HandleVendorRequest(void); + +void SetDMA(BYTE p5, BYTE p3, BYTE px) +{ + XVAL(0xF80B) = 0; + XVAL(0xF80C) = p5-1; + + switch(px) + { + case 0: + { + XVAL(0xF80D) = p3; + XVAL(0xF80E) = p3; + break; + } + case 1: + { + XVAL(0xF80D) = p3; + break; + } + case 2: + { + XVAL(0xF80E) = p3; + break; + } + default: + { + break; + } + } +} + +void SendControlResponse(int size) +{ + EP0.len_l = LSB(size); + EP0.len_m = MSB(size); + EP0.len_h = 0; + EP0.cs = 0x40; + while (EP0.cs & 0x40); + EP0CS = 0x05; +} + +void SendData0(WORD size, BYTE offset) +{ + if (size > 0) + { + SetDMA(0x20, 0, 0); + SetDMA(0x20, 0x80, 1); + EP0.ptr_l = usb_buffer_PA>>8; + EP0.ptr_m = usb_buffer_PA>>16; + EP0.ptr_h = usb_buffer_PA>>24; + EP0.offset = offset; + EP0.len_l = LSB(size); + EP0.len_m = MSB(size); + EP0.len_h = 0; + EP0.cs = 0x88; + + while(EP0.cs & 0x80); + } +} + +void SendData1(WORD size, BYTE offset) +{ + if (size > 0) + { + SetDMA(0x20, 0, 0); + SetDMA(0x20, 0x80, 1); + EP1.ptr_l = usb_buffer_PA>>8; + EP1.ptr_m = usb_buffer_PA>>16; + EP1.ptr_h = usb_buffer_PA>>24; + EP1.offset = offset; + EP1.len_l = LSB(size); + EP1.len_m = MSB(size); + EP1.len_h = 0; + EP1.cs = 0x88; + + while(EP1.cs & 0x80); + } +} + +static void SendCSW() +{ + usb_buffer[0] = 'U'; + usb_buffer[1] = 'S'; + usb_buffer[2] = 'B'; + usb_buffer[3] = 'S'; + usb_buffer[4] = scsi_tag[0]; + usb_buffer[5] = scsi_tag[1]; + usb_buffer[6] = scsi_tag[2]; + usb_buffer[7] = scsi_tag[3]; + usb_buffer[8] = scsi_data_residue; + usb_buffer[9] = scsi_data_residue>>8; + usb_buffer[10] = scsi_data_residue>>16; + usb_buffer[11] = scsi_data_residue>>24; + usb_buffer[12] = scsi_status; + + SendData1(13, 0); + usb_have_csw_ready = 0; + scsi_data_residue = 0; +} + +static void SendCSW2() +{ + while(EP1.cs & bmSTALL); + while((EP1.r17 & 0x80)==0) + { + if ((XVAL(0xF010) & 0x20)==0) + { + usb_have_csw_ready = 0; + return; + } + } + + while(EP1.cs & 0x40); + while(EP2.cs & 0x40); + while(EP3.cs & 0x40); + while(EP4.cs & 0x40); + + EP1.fifo = 'U'; + EP1.fifo = 'S'; + EP1.fifo = 'B'; + EP1.fifo = 'S'; + EP1.fifo = scsi_tag[0]; + EP1.fifo = scsi_tag[1]; + EP1.fifo = scsi_tag[2]; + EP1.fifo = scsi_tag[3]; + EP1.fifo = scsi_data_residue; + EP1.fifo = scsi_data_residue>>8; + EP1.fifo = scsi_data_residue>>16; + EP1.fifo = scsi_data_residue>>24; + EP1.fifo = scsi_status; + EP1.len_l = 13; + EP1.len_m = 0; + EP1.len_h = 0; + EP1.cs = 0x40; + usb_have_csw_ready = 0; + scsi_data_residue = 0; +} + +void InitUSB(void) +{ + BYTE b; + + usb_irq = 0; + usb_received_data_ready = 0; + usb_have_csw_ready = 0; + usb_speed = 0; + EP1.ptr_l = usb_buffer_PA>>8; + EP1.ptr_m = usb_buffer_PA>>16; + EP1.ptr_h = usb_buffer_PA>>24; + EP1.r8 = 0x10; + EP1.offset = 0; + EP2.ptr_l = usb_buffer_PA>>8; + EP2.ptr_m = usb_buffer_PA>>16; + EP2.ptr_h = usb_buffer_PA>>24; + EP2.r8 = 0x10; + EP2.offset = 0; + + if (WARMSTATUS & 2) //USB warm start + { + if ((USBSTAT & bmSpeed) == bmSuperSpeed) + { + usb_speed = bmSuperSpeed; + } + else if ((USBSTAT & bmSpeed) == bmHighSpeed) + { + usb_speed = bmHighSpeed; + } + else if ((USBSTAT & bmSpeed) == bmFullSpeed) + { + usb_speed = bmFullSpeed; + } + else + { + usb_speed = 0; + } + + EX1 = 1; + EX0 = 1; + EPIE = bmEP2IRQ | bmEP4IRQ; + scsi_data_residue = 0; + scsi_status = 0; + SendCSW(); + } + else + { + //USB cold start + REGBANK = 6; + XVAL(0xF240) = 2; + XVAL(0xF28C) = 0x36; + XVAL(0xF28D) = 0xD0; + XVAL(0xF28E) = 0x98; + REGBANK = 0; + EPIE = bmEP2IRQ | bmEP4IRQ; + USBCTL = bmAttach | bmSuperSpeed; + + XVAL(0xFA38) |= 2; + + EX1 = 1; + EX0 = 1; + for (b = 0; b < 250; b++); + } +} + +void usb_isr(void) __interrupt USB_VECT +{ + usb_irq = USBIRQ; + + if (usb_irq & 0x20) + { + USBIRQ = 0x20; + } + + if (usb_irq & 0x10) + { + USBIRQ = 0x10; + } + + if (usb_irq & bmSpeedChange) + { + USBIRQ = bmSpeedChange; + if ((USBSTAT & bmSpeed) == bmSuperSpeed) + { + usb_speed = bmSuperSpeed; + } + else if ((USBSTAT & bmSpeed) == bmHighSpeed) + { + usb_speed = bmHighSpeed; + } + else if ((USBSTAT & bmSpeed) == bmFullSpeed) + { + usb_speed = bmFullSpeed; + } + else + { + usb_speed = 0; + } + } + + if (usb_irq & 0x40) + { + USBIRQ = 0x40; + } + + UsbIntStsF087 = XVAL(0xF087); + UsbIntStsF086 = XVAL(0xF086); + UsbIntStsF082 = XVAL(0xF082); + UsbIntStsF080 = XVAL(0xF080); + + if (UsbIntStsF082 & 0x80) + { + XVAL(0xF082) = 0x80; + } + + if (UsbIntStsF082 & 0x40) + { + XVAL(0xF082) = 0x40; + } + + if (UsbIntStsF080 & 1) + { + XVAL(0xF080) = 1; + if (EP0CS & bmSUDAV) + { + bmRequestType = SETUPDAT[0]; + bRequest = SETUPDAT[1]; + wValue = SETUPDAT[2] | (SETUPDAT[3] << 8); + wIndex = SETUPDAT[4] | (SETUPDAT[5] << 8); + wLength = SETUPDAT[6] | (SETUPDAT[7] << 8); + } + } + + if (XVAL(0xF082) & 0x20) + { + XVAL(0xF082) = 0x20; + } + + if (XVAL(0xF081) & 0x10) + { + XVAL(0xF081) = 0x10; + } + + if (XVAL(0xF081) & 0x20) + { + XVAL(0xF081) = 0x20; + } + + if (UsbIntStsF080 | UsbIntStsF082 | UsbIntStsF086 | UsbIntStsF087 | usb_irq) + { + EX0 = 0; + } +} + +void ep_isr(void) __interrupt EP_VECT +{ + BYTE interrupts = (EPIRQ & (bmEP2IRQ | bmEP4IRQ)); + if (interrupts & bmEP2IRQ) + { + EPIE &= ~bmEP2IRQ; //disable this + EPIRQ = bmEP2IRQ; //acknowledge it + usb_received_data_ready |= bmEP2IRQ; + } + + if (interrupts & bmEP4IRQ) + { + EPIE &= ~bmEP4IRQ; //disable this + EPIRQ = bmEP4IRQ; //acknowledge it + usb_received_data_ready |= bmEP4IRQ; + } +} + +static void ResetEPs() +{ + EPIE = bmEP2IRQ | bmEP4IRQ; + EP1.cs = 0; + EP2.cs = 0; + EP3.cs = 0; + EP4.cs = 0; +} + +static void HandleControlRequest(void) +{ + BYTE res; + switch(bmRequestType & 0x60) + { + case 0: + res = HandleStandardRequest(); + break; + case 0x20: + res = HandleClassRequest(); + break; + case 0x40: + res = HandleVendorRequest(); + break; + default: + res = FALSE; + } + + if (!res) + { + EP0CS = wLength ? bmEP0STALL : bmEP0NAK; + } +} + +void HandleUSBEvents(void) +{ + if (UsbIntStsF080 | UsbIntStsF082 | UsbIntStsF086 | UsbIntStsF087 | usb_irq) + { + if (usb_irq) + { + if (usb_irq & 0x40) + { + USBCTL &= ~bmAttach; + ResetEPs(); + XVAL(0xFE88) = 0; + XVAL(0xFE82) = 0x10; + while(XVAL(0xFE88)!=2); + USBCTL = bmAttach; + } + + if (usb_irq & bmSpeedChange) + { + ResetEPs(); + } + + usb_irq = 0; + } + else + { + if (UsbIntStsF082 & 0xC0) + { + ResetEPs(); + XVAL(0xF092) = 0; + XVAL(0xF096) = 0; + if (UsbIntStsF082 & 0x40) + { + XVAL(0xF07A) = 1; + } + } + else + { + if (UsbIntStsF080 & 1) + { + HandleControlRequest(); + } + } + + UsbIntStsF080 = 0; + UsbIntStsF082 = 0; + UsbIntStsF086 = 0; + UsbIntStsF087 = 0; + } + + EX0 = 1; + } + + //WHY DOESN'T THIS INTERRUPT FIRE?! + if (1)//usb_received_data_ready) + { + if (1)//usb_received_data_ready & bmEP4IRQ) + { + if (EP4.fifo_count > 0) + { + EP4.cs = 0x40; + + send_keys_enabled = 1; + usb_received_data_ready &= ~bmEP4IRQ; + EPIE |= bmEP4IRQ; + } + } + + if (usb_received_data_ready & bmEP2IRQ) + { + if (EP2.fifo_count == 31) //CBW size + { + BYTE a, b, c, d; + + scsi_data_residue = 0; + /*while(EP1.cs & 0x40); + while(EP2.cs & 0x40); + while(EP3.cs & 0x40); + while(EP4.cs & 0x40);*/ + + a = EP2.fifo; + b = EP2.fifo; + c = EP2.fifo; + d = EP2.fifo; + if ((a=='U') && (b=='S') && (c=='B') && (d=='C')) + { + scsi_tag[0] = EP2.fifo; + scsi_tag[1] = EP2.fifo; + scsi_tag[2] = EP2.fifo; + scsi_tag[3] = EP2.fifo; + scsi_transfer_size = EP2.fifo; + scsi_transfer_size |= ((DWORD)EP2.fifo)<<8; + scsi_transfer_size |= ((DWORD)EP2.fifo)<<16; + scsi_transfer_size |= ((DWORD)EP2.fifo)<<24; + scsi_dir_in = EP2.fifo & 0x80; + scsi_lun = EP2.fifo; + scsi_cdb_size = EP2.fifo; + for(a = 0; a < 16; a++) + { + scsi_cdb[a] = EP2.fifo; + } + + EP2.cs = 0x40; + if (!HandleCDB()) + { + scsi_status = 1; + if (scsi_transfer_size == 0) + { + EP1.cs = bmSTALL; + } + else if (scsi_dir_in) + { + EP1.cs = bmSTALL; + } + else + { + EP2.cs = bmSTALL; + } + } + + usb_have_csw_ready = 1; + } + else + { + EP2.cs = 0x40; + EP2.cs = 4; + } + } + else + { + EP2.cs = 0x40; + EP2.cs = 4; + } + + usb_received_data_ready &= ~bmEP2IRQ; + EPIE |= bmEP2IRQ; + } + } + + if (usb_have_csw_ready) + { + SendCSW2(); + } +} diff --git a/firmware/usb.h b/firmware/usb.h new file mode 100644 index 0000000..310fd66 --- /dev/null +++ b/firmware/usb.h @@ -0,0 +1,22 @@ +#ifndef _USB_H_INCLUDED +#define _USB_H_INCLUDED + +void InitUSB(void); +void HandleUSBEvents(void); +void SendControlResponse(int size); +void SendData0(WORD size, BYTE offset); +void SendData1(WORD size, BYTE offset); +void SetDMA(BYTE p5, BYTE p3, BYTE px); + +extern BYTE bmRequestType; +extern BYTE bRequest; +extern WORD wValue; +extern WORD wIndex; +extern WORD wLength; + +extern BYTE usb_speed; +extern __xdata __at usb_buffer_VA volatile BYTE usb_buffer[1024]; +extern __xdata volatile BYTE usb_received_data_ready; +extern __xdata volatile BYTE usb_have_csw_ready; + +#endif diff --git a/patch/base.c b/patch/base.c new file mode 100644 index 0000000..04945b3 --- /dev/null +++ b/patch/base.c @@ -0,0 +1,370 @@ +#include "defs.h" +#include "equates.h" + +#define FEATURE_CHANGE_PASSWORD +//#define FEATURE_EXPOSE_HIDDEN_PARTITION + +#define NUM_LBAS 0xE6EA40UL //this needs to be even! (round down) + +//SCSI command codes +#define SCSI_06 0x06 +#define SCSI_06_XPEEK 0x06 +#define SCSI_06_XPOKE 0x07 +#define SCSI_06_IPEEK 0x08 +#define SCSI_06_IPOKE 0x09 +#define SCSI_START_STOP_UNIT 0x1B +#define SCSI_READ_FORMAT_CAPACITIES 0x23 +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_SECTOR 0x28 +#define SCSI_WRITE_SECTOR 0x2A + +void memset(BYTE* s, BYTE c, int size) +{ + int i; + for (i = 0; i < size; i++) + { + *s = c; + s++; + } +} + +void SendData(int size) +{ + int i; + + while(EP1.cs & bmSTALL); + while((EP1.r17 & 0x80)==0) + { + if ((XVAL(0xF010) & 0x20)==0) + { + return; + } + } + + while(EP1.cs & 0x40); + while(EP2.cs & 0x40); + while(EP3.cs & 0x40); + while(EP4.cs & 0x40); + + for (i = 0; i < size; i++) + { + EP1.fifo = EPBUF[i]; + } + + EP1.len_l = size & 0xFF; + EP1.len_m = (size >> 8) & 0xFF; + EP1.len_h = 0; + EP1.cs = 0x40; +} + +void SendCSW(void) +{ + memset(EPBUF, 0, 13); + EPBUF[0] = 'U'; + EPBUF[1] = 'S'; + EPBUF[2] = 'B'; + EPBUF[3] = 'S'; + EPBUF[4] = scsi_tag[3]; + EPBUF[5] = scsi_tag[2]; + EPBUF[6] = scsi_tag[1]; + EPBUF[7] = scsi_tag[0]; + SendData(13); +} + +//Disconnects and then re-enumerates. +void RecycleUSBConnection(void) +{ + USBCTL &= ~bmAttach; + EPIE = bmEP2IRQ; + EP1.cs = 0; + EP2.cs = 0; + XVAL(0xFE88) = 0; + XVAL(0xFE82) = 0x10; + while (XVAL(0xFE88) != 2); + USBCTL = bmAttach; +} + +#ifdef FEATURE_EXPOSE_HIDDEN_PARTITION + +//HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status, +// since we don't yet know what RAM is safe to use. +BOOL IsHiddenAreaVisible(void) +{ + return WARMSTATUS & 0x80; +} + +//HACK: We're using an unused bit of SYSTEM register 0xFA38 to hold the hidden status, +// since we don't yet know what RAM is safe to use. +void SetHiddenAreaVisibility(BOOL visible) +{ + if (visible) + { + WARMSTATUS |= 0x80; + } + else + { + WARMSTATUS &= 0x7F; + } +} + +void WaitTenSeconds(void) +{ + WORD i, j; + + for (i = 0; i < 65535; i++) + { + for (j = 0; j < 1000; j++) + { + //Do nothing + } + } +} + +#endif + +/* +void HandleControlRequest(void) +{ + if (bmRequestType & 0x20) + { + //Handle class request + } + else if (bmRequestType & 0x40) + { + //Handle vendor request + } + else + { + //Handle standard request + } +} +*/ + +/* +void EndpointInterrupt(void) +{ + __asm + push ACC + push DPH + push DPL + //If no interrupts fired, get out + mov DPTR, #EPIRQ + movx A, @DPTR + jz 000001$ + //Let the firmware know these events happened, so it can handle them + mov B, A + mov DPTR, #FW_EPIRQ + movx A, @DPTR + orl A, B + movx @DPTR, A + //Disable those interrupts so they don't fire again until we're done with them + mov A, #0xFF + xrl A, B + mov DPTR, #EPIE + movx @DPTR, A + //Acknowledge the interrupts + mov A, B + mov DPTR, #EPIRQ + movx @DPTR, A +000001$:pop DPL + pop DPH + pop ACC + reti + __endasm; +} + +void HandleEndpointInterrupt(void) +{ + //Handle incoming endpoint data +} +*/ + +#ifdef FEATURE_EXPOSE_HIDDEN_PARTITION + +void HandleCDB(void) +{ + unsigned long lba; + + switch(scsi_cdb[0]) + { + case SCSI_06: + { + switch (scsi_cdb[1]) + { + case SCSI_06_XPEEK: + { + EPBUF[0] = XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]); + SendData(1); + break; + } + case SCSI_06_XPOKE: + { + XVAL((scsi_cdb[2] << 8) | scsi_cdb[3]) = scsi_cdb[4]; + SendData(1); + break; + } + case SCSI_06_IPEEK: + { + EPBUF[0] = IVAL(scsi_cdb[2]); + SendData(1); + break; + } + case SCSI_06_IPOKE: + { + IVAL(scsi_cdb[2]) = scsi_cdb[3]; + SendData(1); + break; + } + default: + { + __asm + ljmp #DEFAULT_CDB_HANDLER + __endasm; + } + } + break; + } + case SCSI_START_STOP_UNIT: + { + //Are we being stopped? + if (scsi_cdb[4] == 0x02) + { + //Yes, set the other section as the visible one + SetHiddenAreaVisibility(!IsHiddenAreaVisible()); + + //Send the CSW + SendCSW(); + + //Wait and re-enumerate + WaitTenSeconds(); + RecycleUSBConnection(); + } + else + { + //No, let things continue normally + __asm + ljmp #DEFAULT_CDB_HANDLER + __endasm; + } + break; + } + case SCSI_READ_FORMAT_CAPACITIES: + { + lba = NUM_LBAS / 2; + + memset(EPBUF, 0, 12); + EPBUF[3] = 0x08; //capacity list length + EPBUF[4] = lba >> 24; + EPBUF[5] = lba >> 16; + EPBUF[6] = lba >> 8; + EPBUF[7] = lba & 0xFF; + EPBUF[8] = 0x02; //descriptor code (formatted media) + EPBUF[10] = 0x02; //block length (512 bytes/sector) + SendData(12); + break; + } + case SCSI_READ_CAPACITY: + { + lba = (NUM_LBAS / 2) - 1; + + memset(EPBUF, 0, 8); + EPBUF[0] = lba >> 24; + EPBUF[1] = lba >> 16; + EPBUF[2] = lba >> 8; + EPBUF[3] = lba & 0xFF; + EPBUF[6] = 0x02; //block length (512 bytes/sector) + SendData(8); + break; + } + case SCSI_READ_SECTOR: //TODO: we should handle the other READ(X) commands as well + { + //Get the passed-in LBA + lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000; + lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000; + lba |= (scsi_cdb[4] << 8) & 0xFF00; + lba |= scsi_cdb[5]; + + //Shift it if necessary + if (IsHiddenAreaVisible()) + { + lba += NUM_LBAS / 2; + } + + //Save it + scsi_cdb[2] = (lba >> 24) & 0xFF; + scsi_cdb[3] = (lba >> 16) & 0xFF; + scsi_cdb[4] = (lba >> 8) & 0xFF; + scsi_cdb[5] = lba & 0xFF; + + //Let the firmware do its thing + __asm + ljmp #DEFAULT_READ_SECTOR_HANDLER + __endasm; + } + case SCSI_WRITE_SECTOR: //TODO: we should handle the other WRITE(x) commands as well + { + //Get the passed-in LBA + lba = ((unsigned long)(scsi_cdb[2]) << 24) & 0xFF000000; + lba |= ((unsigned long)(scsi_cdb[3]) << 16) & 0xFF0000; + lba |= (scsi_cdb[4] << 8) & 0xFF00; + lba |= scsi_cdb[5]; + + //Shift it if necessary + if (IsHiddenAreaVisible()) + { + lba += NUM_LBAS / 2; + } + + //Save it + scsi_cdb[2] = (lba >> 24) & 0xFF; + scsi_cdb[3] = (lba >> 16) & 0xFF; + scsi_cdb[4] = (lba >> 8) & 0xFF; + scsi_cdb[5] = lba & 0xFF; + + //Let the firmware do its thing + __asm + ljmp #DEFAULT_CDB_HANDLER + __endasm; + } + default: + __asm + ljmp #DEFAULT_CDB_HANDLER + __endasm; + } +} + +#endif + +//Called in the firmware's infinite loop. +/* +void LoopDo(void) +{ +} +*/ + +#ifdef FEATURE_CHANGE_PASSWORD + +void SetPassword(BYTE* address) +{ + int i; + for (i = 0; i < 16; i++) + { + *(address + i) = 'A'; + } +} + +void PasswordReceived() +{ + if (EPBUF[0]) + { + SetPassword(EPBUF); + + } + + if (EPBUF[0x10]) + { + SetPassword(EPBUF + 0x10); + } +} + +#endif diff --git a/patch/build.bat b/patch/build.bat new file mode 100644 index 0000000..95c98ee --- /dev/null +++ b/patch/build.bat @@ -0,0 +1,50 @@ +@ECHO OFF + +REM Set things up and create bin directory if necessary. +SETLOCAL ENABLEDELAYEDEXPANSION +SET BUILD_FILES= +IF NOT EXIST bin\NUL MKDIR bin + +REM Generate .h C file for compilation. +ECHO *** Generating C .h file... +..\tools\Injector.exe /action=GenerateHFile /firmware=fw.bin /output=equates.h +IF ERRORLEVEL 1 GOTO ERRORS + +REM Build each file in the list. +REM NOTE: This needs to change if more code files or sections are added. +FOR %%A IN ( +base +) DO ( +ECHO *** Building %%A.c... +sdcc --model-small -mmcs51 -pdefcpu -c -obin\%%A.rel %%A.c +IF ERRORLEVEL 1 GOTO ERRORS +SET "BUILD_FILES=!BUILD_FILES! bin\%%A.rel" +) + +REM Retrieve free space for each section in the image. +ECHO *** Retrieving free space in image... +..\tools\Injector.exe /action=FindFreeBlock /firmware=fw.bin /section=Base /output=bin\free.txt +SET BASE_FREE_ADDR= +FOR /F "delims=" %%i IN (bin\free.txt) DO SET BASE_FREE_ADDR=!BASE_FREE_ADDR! %%i +DEL bin\free.txt + +REM Build Intel Hex and BIN versions of combined file. +ECHO *** Linking... +sdcc --model-small --code-loc %BASE_FREE_ADDR% --xram-size 0x400 --xram-loc 0x7C00 -o bin\output.hex %BUILD_FILES% +..\tools\hex2bin bin\output.hex + +REM Build patched image from assembled image. +REM NOTE: This needs to change if more code files or sections are added. +ECHO *** Injecting... +..\tools\Injector.exe /action=ApplyPatches /firmware=fw.bin /basecode=bin\output.bin /baserst=bin\base.rst /output=bin\fw.bin +IF ERRORLEVEL 1 GOTO ERRORS + +GOTO END + +:ERRORS +ECHO *** There were errors^^! *** + +:END +ECHO *** Done. + +ENDLOCAL diff --git a/patch/defs.h b/patch/defs.h new file mode 100644 index 0000000..d5d1c4c --- /dev/null +++ b/patch/defs.h @@ -0,0 +1,287 @@ +#ifndef DEFS_H +#define DEFS_H + +#define MSB(word) (BYTE)(((WORD)(word) >> 8) & 0xff) +#define LSB(word) (BYTE)((WORD)(word) & 0xff) + +#define XVAL(addr) (*( __xdata volatile unsigned char *)(addr)) +#define IVAL(addr) (*( __idata volatile unsigned char *)(addr)) + +typedef unsigned char BYTE; +typedef unsigned short WORD; +typedef unsigned long DWORD; +typedef __bit BOOL; +typedef __bit bit; +#define TRUE 1 +#define FALSE 0 + +#define USB_VECT 0 +#define TMR0_VECT 1 +#define EP_VECT 2 +#define TMR1_VECT 3 +#define COM0_VECT 4 + +#define bmAttach 0x80 +#define bmSpeed 7 +#define bmSuperSpeed 4 +#define bmHighSpeed 0 +#define bmFullSpeed 1 +#define bmSpeedChange 0x80 +#define bmEP2IRQ 2 +#define bmEP0ACK 1 +#define bmEP0NAK 2 +#define bmEP0IN 4 +#define bmEP0STALL 8 +#define bmSUDAV 0x80 +#define bmSTALL 2 + +#define bmNandReady 1 + +#define bmNandDma0 0 +#define bmNandDma1 0x80 +#define bmNandDmaRead 0 +#define bmNandDmaWrite 0x40 + +#define bmDmaCmd 7 +#define bmDmaCopy 2 +#define bmDmaFill 4 +#define bmDmaWidth8 0 +#define bmDmaWidth16 0x40 +#define bmDmaWidth32 0x80 + +#define bmPRAM 1 + +// ------------------------------------------------------------------------------------------------ +// * SFRs +// * ------------------------------------------------------------------------------------------------ +// BYTE Register +__sfr __at (0x80) P0 ; +__sfr __at (0x90) P1 ; +__sfr __at (0xA0) P2 ; +__sfr __at (0xB0) P3 ; +__sfr __at (0xD0) PSW ; +__sfr __at (0xE0) ACC ; +__sfr __at (0xF0) B ; +__sfr __at (0x81) SP ; +__sfr __at (0x82) DPL ; +__sfr __at (0x83) DPH ; +__sfr __at (0x87) PCON; +__sfr __at (0x88) TCON; +__sfr __at (0x89) TMOD; +__sfr __at (0x8A) TL0 ; +__sfr __at (0x8B) TL1 ; +__sfr __at (0x8C) TH0 ; +__sfr __at (0x8D) TH1 ; +__sfr __at (0xA8) IE ; +__sfr __at (0xB8) IP ; +__sfr __at (0x98) SCON; +__sfr __at (0x99) SBUF; + +/* BIT Register */ +/* PSW */ +__sbit __at (0xD7) CY ; +__sbit __at (0xD6) AC ; +__sbit __at (0xD5) F0 ; +__sbit __at (0xD4) RS1 ; +__sbit __at (0xD3) RS0 ; +__sbit __at (0xD2) OV ; +__sbit __at (0xD0) P ; + +/* TCON */ +__sbit __at (0x8F) TF1 ; +__sbit __at (0x8E) TR1 ; +__sbit __at (0x8D) TF0 ; +__sbit __at (0x8C) TR0 ; +__sbit __at (0x8B) IE1 ; +__sbit __at (0x8A) IT1 ; +__sbit __at (0x89) IE0 ; +__sbit __at (0x88) IT0 ; + +/* IE */ +__sbit __at (0xAF) EA ; +__sbit __at (0xAC) ES ; +__sbit __at (0xAB) ET1 ; +__sbit __at (0xAA) EX1 ; +__sbit __at (0xA9) ET0 ; +__sbit __at (0xA8) EX0 ; + +/* IP */ +__sbit __at (0xBC) PS ; +__sbit __at (0xBB) PT1 ; +__sbit __at (0xBA) PX1 ; +__sbit __at (0xB9) PT0 ; +__sbit __at (0xB8) PX0 ; + +/* P3 */ +__sbit __at (0xB7) RD ; +__sbit __at (0xB6) WR ; +__sbit __at (0xB5) T1 ; +__sbit __at (0xB4) T0 ; +__sbit __at (0xB3) INT1; +__sbit __at (0xB2) INT0; +__sbit __at (0xB1) TXD ; +__sbit __at (0xB0) RXD ; + +/* SCON */ +__sbit __at (0x9F) SM0 ; +__sbit __at (0x9E) SM1 ; +__sbit __at (0x9D) SM2 ; +__sbit __at (0x9C) REN ; +__sbit __at (0x9B) TB8 ; +__sbit __at (0x9A) RB8 ; +__sbit __at (0x99) TI ; +__sbit __at (0x98) RI ; + +// ------------------------------------------------------------------------------------------------ +// Xdata F000-F3FF USB Registers +// ------------------------------------------------------------------------------------------------ +// some banking registers switching +// value: 0-7, default: 0 +__xdata __at 0xF000 volatile BYTE REGBANK; +__xdata __at 0xF008 volatile BYTE USBCTL; +__xdata __at 0xF009 volatile BYTE USBSTAT; +__xdata __at 0xF027 volatile BYTE USBIRQ; +__xdata __at 0xF020 volatile BYTE EPIRQ; +__xdata __at 0xF030 volatile BYTE EPIE; +__xdata __at 0xF048 volatile BYTE EP0CS; +__xdata __at 0xF0B8 volatile BYTE SETUPDAT[8]; + +typedef struct +{ + BYTE r0,r1,r2,r3,r4; + BYTE ptr_l, ptr_m, ptr_h; //buffer ptr = buf_pa>>8 + BYTE r8,r9; + BYTE ofs; // buffer offset, data addr will be ptr<<8 + ofs*0x200 + BYTE rB; + BYTE len_l, len_m, len_h; //C,D,E + BYTE rF,r10,r11,r12; + BYTE cs; //13 + BYTE r14,r15,r16,r17,r18,r19; + BYTE fifo_count; + BYTE r1B; + BYTE fifo; //1C +} EPREGS; + +__xdata __at 0xF1C0 volatile EPREGS EP0; +__xdata __at 0xF200 volatile EPREGS EP1; +__xdata __at 0xF240 volatile EPREGS EP2; +__xdata __at 0xF280 volatile EPREGS EP3; +__xdata __at 0xF2C0 volatile EPREGS EP4; + +typedef struct +{ + BYTE raw_cmd; + BYTE u1[3]; + BYTE raw_addr; + BYTE u5[3]; + BYTE raw_data; + BYTE r9; + BYTE uA[2]; + BYTE rC; + BYTE uD[3]; + BYTE r10; + BYTE u11[7]; + BYTE r18; + BYTE u19[5]; + BYTE status; // .0 - R/nB + BYTE u1F[0x19]; + BYTE r38, r39, r3A; + BYTE u3B; + BYTE r3C, r3D; + BYTE u3E[2]; + BYTE r40; + BYTE dma_size; // DMA size in KB + BYTE r42; + BYTE dma_mode; // DMA modes + BYTE u44[3]; + BYTE r47; + BYTE u48[0x14]; + BYTE r5C; // nand command + // DMA command. |=1 to go, wait until .0 cleared + BYTE dma_cmd; + BYTE u61[0x0B]; + BYTE dma1_page; // DMA1 start page. Autoincrements + BYTE u6D[3]; + BYTE dma0_page; // DMA0 start page. Autoincrements + BYTE u71[3]; + // DMA1 PA. This pseudo reg sets dma1_page actually. RAZ + BYTE dma1_ptr0, dma1_ptr1, dma1_ptr2, dma1_ptr3; + // DMA0 PA. This pseudo reg sets w_dma_page actually. RAZ + BYTE dma0_ptr0, dma0_ptr1, dma0_ptr2, dma0_ptr3; + BYTE u7C[4]; + BYTE r80; + BYTE u81[0x1B]; + BYTE page_size_l, page_size_h; // 9C full page size with spare + BYTE r9E, r9F; + BYTE uA0[0x4C]; + BYTE rEC; + BYTE uED[0x13]; +} NANDREGS; + +__xdata __at 0xF400 volatile NANDREGS NFC0; +__xdata __at 0xF500 volatile NANDREGS NFC1; + +__xdata __at 0xF608 volatile BYTE NANDCSOUT; +__xdata __at 0xF618 volatile BYTE NANDCSDIR; +//F638, F639 - scrambler control +//F638 | 18 & 7F - turn off descrambler +__xdata __at 0xF700 volatile NANDREGS NFCX; + +// DMA copy source / fill destination physical address +__xdata __at 0xF900 volatile BYTE DMASRCL; +__xdata __at 0xF901 volatile BYTE DMASRCM; +__xdata __at 0xF902 volatile BYTE DMASRCH; + +// DMA copy destination physical address +__xdata __at 0xF904 volatile BYTE DMADSTL; +__xdata __at 0xF905 volatile BYTE DMADSTM; +__xdata __at 0xF906 volatile BYTE DMADSTH; + +// DMA copy size in bytes (always in bytes, regardless of cmd width) +__xdata __at 0xF908 volatile BYTE DMASIZEL; +__xdata __at 0xF909 volatile BYTE DMASIZEM; +__xdata __at 0xF90A volatile BYTE DMASIZEH; + +// DMA fill value +__xdata __at 0xF90C volatile BYTE DMAFILL0; +__xdata __at 0xF90D volatile BYTE DMAFILL1; +__xdata __at 0xF90E volatile BYTE DMAFILL2; +__xdata __at 0xF90F volatile BYTE DMAFILL3; + +// DMA command +__xdata __at 0xF930 volatile BYTE DMACMD; + +// ------------------------------------------------------------------------------------------------ +// Xdata FA00-FAFF SYSTEM Registers +// ------------------------------------------------------------------------------------------------ +__xdata __at 0xFA14 volatile BYTE GPIO0DIR; +__xdata __at 0xFA15 volatile BYTE GPIO0OUT; +__xdata __at 0xFA38 volatile BYTE WARMSTATUS; + +// XDATA banking +// XDATA consists of 3 mapped areas: BANK0,1,2 +// BANK0 start is fixed at 0000, BANK1,2 starts at variable addresses +// in case of overlapped addresses a bank with higher number has higher priority + +// xdata BANK0 mapping registers +// maps XDATA VA 0000 to PA=BANK0PAH:L<<9, size - up to BANK1/2 +__xdata __at 0xFA40 volatile BYTE BANK0PAL; +__xdata __at 0xFA41 volatile BYTE BANK0PAH; + +// xdata BANK1 mapping registers +// maps XDATA VA=(BANK1VA & 0xFE)<<8 to PA=BANK1PAH:L<<9, size - up to BANK2 +__xdata __at 0xFA42 volatile BYTE BANK1VA; +__xdata __at 0xFA43 volatile BYTE BANK1PAL; +__xdata __at 0xFA44 volatile BYTE BANK1PAH; + +// xdata BANK2 mapping registers +// maps XDATA VA=(BANK2VA & 0xFE)<<8 to PA=BANK2PAH:L<<9, size - up to F000 +__xdata __at 0xFA45 volatile BYTE BANK2VA; +__xdata __at 0xFA46 volatile BYTE BANK2PAL; +__xdata __at 0xFA47 volatile BYTE BANK2PAH; + +// PRAM/PROM switching with restart +// value: bit0 =0 - run from PROM, =1 - run from PRAM. Changing this bit causes CPU restart! +__xdata __at 0xFA48 volatile BYTE PRAMCTL; + +#endif diff --git a/templates/BNdummy.bin b/templates/BNdummy.bin new file mode 100644 index 0000000..6bfee1d Binary files /dev/null and b/templates/BNdummy.bin differ diff --git a/templates/FWdummy.bin b/templates/FWdummy.bin new file mode 100644 index 0000000..49c8ac5 Binary files /dev/null and b/templates/FWdummy.bin differ