/// <summary> /// Erase a block in the flash memory. /// </summary> private async Task <bool> EraseMemoryRange(MemoryRange range, CancellationToken cancellationToken) { this.logger.AddUserMessage("Erasing."); await this.vehicle.SetDeviceTimeout(TimeoutScenario.EraseMemoryBlock); Query <byte> eraseRequest = this.vehicle.CreateQuery <byte>( () => this.protocol.CreateFlashEraseBlockRequest(range.Address), this.protocol.ParseFlashEraseBlock, cancellationToken); eraseRequest.MaxTimeouts = 3; Response <byte> eraseResponse = await eraseRequest.Execute(); if (eraseResponse.Status != ResponseStatus.Success) { this.logger.AddUserMessage("Unable to erase flash memory: " + eraseResponse.Status.ToString()); this.RequestDebugLogs(cancellationToken); return(false); } if (eraseResponse.Value != 0x00) { this.logger.AddUserMessage("Unable to erase flash memory. Code: " + eraseResponse.Value.ToString("X2")); this.RequestDebugLogs(cancellationToken); return(false); } return(true); }
private bool ShouldProcess(MemoryRange range, BlockType relevantBlocks) { if ((range.ActualCrc == range.DesiredCrc) && (this.writeType != WriteType.TestWrite)) { return(false); } // Skip irrelevant blocks. if ((range.Type & relevantBlocks) == 0) { return(false); } return(true); }
/// <summary> /// Copy a single memory range to the PCM. /// </summary> private async Task <bool> WriteMemoryRange( MemoryRange range, byte[] image, bool justTestWrite, CancellationToken cancellationToken) { int devicePayloadSize = vehicle.DeviceMaxSendSize - 12; // Headers use 10 bytes, sum uses 2 bytes. for (int index = 0; index < range.Size; index += devicePayloadSize) { if (cancellationToken.IsCancellationRequested) { return(false); } await this.vehicle.SendToolPresentNotification(); int startAddress = (int)(range.Address + index); int thisPayloadSize = Math.Min(devicePayloadSize, (int)range.Size - index); Message payloadMessage = protocol.CreateBlockMessage( image, startAddress, thisPayloadSize, startAddress, justTestWrite ? BlockCopyType.TestWrite : BlockCopyType.Copy); logger.AddUserMessage( string.Format( "Sending payload with offset 0x{0:X4}, start address 0x{1:X6}, length 0x{2:X4}.", index, startAddress, thisPayloadSize)); await this.vehicle.WritePayload(payloadMessage, cancellationToken); // Not checking the success or failure here. // The debug pane will show if anything goes wrong, and the CRC check at the end will alert the user. // TODO: log errors during test writes! } return(true); }
/// <summary> /// Copy a single memory range to the PCM. /// </summary> private async Task <Response <bool> > WriteMemoryRange( MemoryRange range, byte[] image, bool justTestWrite, DateTime startTime, UInt32 totalSize, UInt32 bytesRemaining, CancellationToken cancellationToken) { int retryCount = 0; int devicePayloadSize = vehicle.DeviceMaxFlashWriteSendSize - 12; // Headers use 10 bytes, sum uses 2 bytes. for (int index = 0; index < range.Size; index += devicePayloadSize) { if (cancellationToken.IsCancellationRequested) { return(Response.Create(ResponseStatus.Cancelled, false, retryCount)); } await this.vehicle.SendToolPresentNotification(); int startAddress = (int)(range.Address + index); UInt32 thisPayloadSize = (UInt32)Math.Min(devicePayloadSize, (int)range.Size - index); logger.AddDebugMessage( string.Format( "Sending payload with offset 0x{0:X4}, start address 0x{1:X6}, length 0x{2:X4}.", index, startAddress, thisPayloadSize)); Message payloadMessage = protocol.CreateBlockMessage( image, startAddress, (int)thisPayloadSize, startAddress, justTestWrite ? BlockCopyType.TestWrite : BlockCopyType.Copy); string timeRemaining; TimeSpan elapsed = DateTime.Now - startTime; UInt32 totalWritten = totalSize - bytesRemaining; // Wait 10 seconds before showing estimates. if (elapsed.TotalSeconds < 10) { timeRemaining = "Measuring write speed..."; } else { UInt32 bytesPerSecond = (UInt32)(totalWritten / elapsed.TotalSeconds); // Don't divide by zero. if (bytesPerSecond > 0) { UInt32 secondsRemaining = (UInt32)(bytesRemaining / bytesPerSecond); timeRemaining = TimeSpan.FromSeconds(secondsRemaining).ToString("mm\\:ss"); } else { timeRemaining = "??:??"; } } logger.AddUserMessage( string.Format( "0x{0:X6}\t{1}%\t{2}", startAddress, totalWritten * 100 / totalSize, timeRemaining)); await this.vehicle.SetDeviceTimeout(TimeoutScenario.WriteMemoryBlock); // WritePayload contains a retry loop, so if it fails, we don't need to retry at this layer. Response <bool> response = await this.vehicle.WritePayload(payloadMessage, cancellationToken); if (response.Status != ResponseStatus.Success) { return(Response.Create(ResponseStatus.Error, false, response.RetryCount)); } bytesRemaining -= thisPayloadSize; retryCount += response.RetryCount; } return(Response.Create(ResponseStatus.Success, true, retryCount)); }
private bool ShouldProcess(MemoryRange range, BlockType relevantBlocks) { return(true); }
/// <summary> /// /// </summary> /// <param name="chipId"></param> /// <returns></returns> public static IList <MemoryRange> GetMemoryRanges(UInt32 chipId, ILogger logger) { IList <MemoryRange> result = null; switch (chipId) { // This is only here as a warning to anyone adding ranges for another chip. // Please read the comments carefully. See case 0x00894471 for the real deal. case 0xFFFF4471: var unused = new MemoryRange[] { // These numbers and descriptions are straight from the intel 28F400B data sheet. // Notice that if you convert the 16 bit word sizes to decimal, they're all // half as big as the description here, in bytes, indicates. new MemoryRange(0x30000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x10000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x04000, 0x0C000, BlockType.Calibration), // 96kb main block new MemoryRange(0x03000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x02000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x02000, BlockType.Boot), // 16kb boot block }; return(null); // Intel 28F800B case 0x0089889D: result = new MemoryRange[] { // These addresses are for a bottom fill chip (B) in byte mode (not word) new MemoryRange(0xE0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0xC0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0xA0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x80000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x60000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x40000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x08000, 0x18000, BlockType.Calibration), // 96kb main block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; // Intel 28F400B case 0x00894471: result = new MemoryRange[] { // These addresses are for a bottom fill chip (B) in byte mode (not word) new MemoryRange(0x60000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x40000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x08000, 0x18000, BlockType.Calibration), // 96kb main block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; case 0x00012258: result = new MemoryRange[] { new MemoryRange(0xF0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xE0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xD0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xC0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xB0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xA0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x90000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x80000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x70000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x60000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x50000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x40000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x30000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x20000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x10000, 0x10000, BlockType.Calibration), // 64kb calibration block new MemoryRange(0x08000, 0x08000, BlockType.Calibration), // 32kb calibration block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; default: logger.AddUserMessage( "Unsupported flash chip ID " + chipId.ToString("X8") + ". " + Environment.NewLine + "The flash memory in this PCM is not supported by this version of PCM Hammer." + Environment.NewLine + "Please look for a thread about this at pcmhacking.net, or create one if necessary." + Environment.NewLine + "We do aim to support for all flash chips over time."); return(null); } // Sanity check the memory ranges UInt32 lastStart = UInt32.MaxValue; for (int index = 0; index < result.Count; index++) { if (index == 0) { UInt32 top = result[index].Address + result[index].Size; if ((top != 512 * 1024) && (top != 1024 * 1024)) { throw new InvalidOperationException("Upper end of memory range must be 512k or 1024k."); } } if (index == result.Count - 1) { if (result[index].Address != 0) { throw new InvalidOperationException("Memory ranges must start at zero."); } } if (lastStart != UInt32.MaxValue) { if (lastStart != result[index].Address + result[index].Size) { throw new InvalidDataException("Top of this range must match base of range above."); } } lastStart = result[index].Address; } return(result); }
/// <summary> /// Factory method. Selects the memory configuration, size, and description. /// </summary> public static FlashChip Create(UInt32 chipId, ILogger logger) { IList <MemoryRange> memoryRanges = null; string description; UInt32 size; switch (chipId) { // This is only here as a warning to anyone adding ranges for another chip. // Please read the comments carefully. See case 0x00894471 for the real data. case 0xFFFF4471: var unused = new MemoryRange[] { // These numbers and descriptions are straight from the intel 28F400B data sheet. // Notice that if you convert the 16 bit word sizes to decimal, they're all // half as big as the description here, in bytes, indicates. new MemoryRange(0x30000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x10000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x04000, 0x0C000, BlockType.Calibration), // 96kb main block new MemoryRange(0x03000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x02000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x02000, BlockType.Boot), // 16kb boot block }; throw new InvalidOperationException("This flash chip ID was not supposed to exist in the wild."); // Intel 28F800B case 0x0089889D: size = 1024 * 1024; description = "Intel 28F800B, 1mb"; memoryRanges = new MemoryRange[] { // These addresses are for a bottom fill chip (B) in byte mode (not word) new MemoryRange(0xE0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0xC0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0xA0000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x80000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x60000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x40000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x08000, 0x18000, BlockType.Calibration), // 96kb main block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; // Intel 28F400B case 0x00894471: size = 512 * 1024; description = "Intel 28F400B, 512kb"; memoryRanges = new MemoryRange[] { // These addresses are for a bottom fill chip (B) in byte mode (not word) new MemoryRange(0x60000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x40000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x08000, 0x18000, BlockType.Calibration), // 96kb main block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; // AM29F800BB case 0x00012258: size = 1024 * 1024; description = "AMD AM29F800BB, 1mb"; memoryRanges = new MemoryRange[] { new MemoryRange(0xF0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xE0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xD0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xC0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xB0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0xA0000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x90000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x80000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x70000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x60000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x50000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x40000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x30000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x20000, 0x10000, BlockType.OperatingSystem), // 64kb main block new MemoryRange(0x10000, 0x10000, BlockType.Calibration), // 64kb calibration block new MemoryRange(0x08000, 0x08000, BlockType.Calibration), // 32kb calibration block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; // IPC case 0x4D696B65: size = 16 * 1024; description = "IPC Calibration"; memoryRanges = new MemoryRange[] { // These addresses are for a bottom fill chip (B) in byte mode (not word) new MemoryRange(0x00000, 0x04000, BlockType.OperatingSystem), // 128kb main block }; break; // IPC1 case 0x6D696B65: size = 112 * 1024; description = "IPC OS + Calibration"; memoryRanges = new MemoryRange[] { new MemoryRange(0x00000, 0x1C000, BlockType.OperatingSystem), }; break; // Both of these have eight 8kb blocks at the low end, the rest are // 64kb. Not sure if they're actually used in any PCMs though. case 0x00898893: // Intel 2F008B3 case 0x008988C1: // Intel 2F800C3 default: string manufacturer; switch ((chipId >> 16)) { case 0x0001: manufacturer = "AMD"; break; case 0x0089: manufacturer = "Intel"; break; default: manufacturer = "Unknown"; break; } logger.AddUserMessage( "Unsupported flash chip ID " + chipId.ToString("X8") + ". Manufacturer: " + manufacturer + Environment.NewLine + "The flash memory in this PCM is not supported by this version of PCM Hammer." + Environment.NewLine + "Please look for a thread about this at pcmhacking.net, or create one if necessary." + Environment.NewLine + "We do aim to add support for all flash chips eventually."); throw new ApplicationException(); } // Sanity check the memory ranges; UInt32 lastStart = UInt32.MaxValue; string chipIdString = chipId.ToString("X8"); for (int index = 0; index < memoryRanges.Count; index++) { if (index == 0) { UInt32 top = memoryRanges[index].Address + memoryRanges[index].Size; if ((top != 16 * 1024) && (top != 112 * 1024) && (top != 512 * 1024) && (top != 1024 * 1024)) { throw new InvalidOperationException(chipIdString + " - Upper end of memory range must be 512k or 1024k, is " + top.ToString("X8")); } if (size != top) { throw new InvalidOperationException(chipIdString + " - Size does not match upper memory block."); } } if (index == memoryRanges.Count - 1) { if (memoryRanges[index].Address != 0) { throw new InvalidOperationException(chipIdString + " - Memory ranges must start at zero."); } } if (lastStart != UInt32.MaxValue) { if (lastStart != memoryRanges[index].Address + memoryRanges[index].Size) { throw new InvalidDataException(chipIdString + " - Top of range " + index + " must match base of range above."); } } lastStart = memoryRanges[index].Address; } return(new FlashChip(chipId, description, size, memoryRanges)); }
/// <summary> /// /// </summary> /// <param name="chipId"></param> /// <returns></returns> public IList <MemoryRange> GetMemoryRanges(UInt32 chipId) { IList <MemoryRange> result = null; switch (chipId) { // This is only here as a warning to anyone adding ranges for another chip. // Please read the comments carefully. See case 0x00894471 for the real deal. case 0xFFFF4471: var unused = new MemoryRange[] { // These numbers and descriptions are straight from the data sheet. // Notice that if you convert the hex sizes to decimal, they're all // half as big as the description indicates. That's wrong. It doesn't // work that way in the PCM, so this would only compare 256 kb. new MemoryRange(0x30000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x10000, 0x10000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x04000, 0x0C000, BlockType.Calibration), // 96kb main block new MemoryRange(0x03000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x02000, 0x01000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x02000, BlockType.Boot), // 16kb boot block }; return(null); // Intel 28F400B case 0x00894471: result = new MemoryRange[] { // All of these addresses and sizes are all 2x what's listed // in the data sheet, because the data sheet table assumes that // "bytes" are 16 bits wide. Which means they're not bytes. But // the data sheet calls them bytes. new MemoryRange(0x60000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x40000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x20000, 0x20000, BlockType.OperatingSystem), // 128kb main block new MemoryRange(0x08000, 0x18000, BlockType.Calibration), // 96kb main block new MemoryRange(0x06000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x04000, 0x02000, BlockType.Parameter), // 8kb parameter block new MemoryRange(0x00000, 0x04000, BlockType.Boot), // 16kb boot block }; break; default: this.logger.AddUserMessage( "Unsupported flash chip ID " + chipId.ToString("X8") + ". " + Environment.NewLine + "The flash memory in this PCM is not supported by this version of PCM Hammer." + Environment.NewLine + "Please look for a thread about this at pcmhacking.net, or create one if necessary." + Environment.NewLine + "We do aim to support for all flash chips over time."); return(null); } // Sanity check the memory ranges UInt32 lastStart = UInt32.MaxValue; for (int index = 0; index < result.Count; index++) { if (index == 0) { UInt32 top = result[index].Address + result[index].Size; if ((top != 512 * 1024) && (top != 1024 * 1024)) { throw new InvalidOperationException("Upper end of memory range must be 512k or 1024k."); } } if (index == result.Count - 1) { if (result[index].Address != 0) { throw new InvalidOperationException("Memory ranges must start at zero."); } } if (lastStart != UInt32.MaxValue) { if (lastStart != result[index].Address + result[index].Size) { throw new InvalidDataException("Top of this range must match base of range above."); } } lastStart = result[index].Address; } return(result); }