/
CKernelVerifier.cs
169 lines (147 loc) · 6.42 KB
/
CKernelVerifier.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace PcmHacking
{
public class CKernelVerifier
{
private readonly byte[] image;
private readonly IEnumerable<MemoryRange> ranges;
private readonly Vehicle vehicle;
private readonly Protocol protocol;
private readonly ILogger logger;
public CKernelVerifier(byte[] image, IEnumerable<MemoryRange> ranges, Vehicle vehicle, Protocol protocol, ILogger logger)
{
this.image = image;
this.ranges = ranges;
this.vehicle = vehicle;
this.protocol = protocol;
this.logger = logger;
}
/// <summary>
/// Get the CRC for each address range in the file that the user wants to flash.
/// </summary>
private void GetCrcFromImage()
{
Crc crc = new Crc();
foreach (MemoryRange range in this.ranges)
{
range.DesiredCrc = crc.GetCrc(this.image, range.Address, range.Size);
}
}
/// <summary>
/// Compare CRCs from the file to CRCs from the PCM.
/// </summary>
public async Task<bool> CompareRanges(
IList<MemoryRange> ranges,
byte[] image,
BlockType blockTypes,
CancellationToken cancellationToken)
{
logger.AddUserMessage("Calculating CRCs from file...");
this.GetCrcFromImage();
logger.AddUserMessage("Requesting CRCs from PCM...");
await this.vehicle.SendToolPresentNotification();
// The kernel will remember (and return) the CRC value of the last block it
// was asked about, which leads to misleading results if you only rewrite
// a single block. So we send a a bogus query to reset the last-used CRC
// value in the kernel.
Query<UInt32> crcReset = this.vehicle.CreateQuery<uint>(
() => this.protocol.CreateCrcQuery(0, 0),
(message) => this.protocol.ParseCrc(message, 0, 0),
cancellationToken);
await crcReset.Execute();
await this.vehicle.SetDeviceTimeout(TimeoutScenario.ReadCrc);
bool successForAllRanges = true;
foreach (MemoryRange range in ranges)
{
if ((range.Type & blockTypes) == 0)
{
this.logger.AddUserMessage(
string.Format(
"Range {0:X6}-{1:X6} - Not needed for this operation.",
range.Address,
range.Address + (range.Size - 1)));
continue;
}
await this.vehicle.SendToolPresentNotification();
this.vehicle.ClearDeviceMessageQueue();
bool success = false;
UInt32 crc = 0;
// You might think that a shorter retry delay would speed things up,
// but 1500ms delay gets CRC results in about 3.5 seconds.
// A 1000ms delay resulted in 4+ second CRC responses, and a 750ms
// delay resulted in 5 second CRC responses. The PCM needs to spend
// its time caculating CRCs rather than responding to messages.
int retryDelay = 1500;
Message query = this.protocol.CreateCrcQuery(range.Address, range.Size);
for (int attempts = 0; attempts < 10; attempts++)
{
if (cancellationToken.IsCancellationRequested)
{
break;
}
await this.vehicle.SendToolPresentNotification();
if (!await this.vehicle.SendMessage(query))
{
// This delay is fast because we're waiting for the bus to be available,
// rather than waiting for the PCM's CPU to finish computing the CRC as
// with the other two delays below.
await Task.Delay(100);
continue;
}
Message response = await this.vehicle.ReceiveMessage();
if (response == null)
{
await Task.Delay(retryDelay);
continue;
}
Response<UInt32> crcResponse = this.protocol.ParseCrc(response, range.Address, range.Size);
if (crcResponse.Status != ResponseStatus.Success)
{
await Task.Delay(retryDelay);
continue;
}
success = true;
crc = crcResponse.Value;
break;
}
this.vehicle.ClearDeviceMessageQueue();
if (!success)
{
this.logger.AddUserMessage("Unable to get CRC for memory range " + range.Address.ToString("X8") + " / " + range.Size.ToString("X8"));
successForAllRanges = false;
continue;
}
range.ActualCrc = crc;
this.logger.AddUserMessage(
string.Format(
"Range {0:X6}-{1:X6} - File: {2:X8} - PCM: {3:X8} - ({4}) - {5}",
range.Address,
range.Address + (range.Size - 1),
range.DesiredCrc,
range.ActualCrc,
range.Type,
range.DesiredCrc == range.ActualCrc ? "Same" : "Different"));
}
await this.vehicle.SendToolPresentNotification();
foreach (MemoryRange range in ranges)
{
if ((range.Type & blockTypes) == 0)
{
continue;
}
if (range.ActualCrc != range.DesiredCrc)
{
return false;
}
}
this.vehicle.ClearDeviceMessageQueue();
return successForAllRanges;
}
}
}