/// <summary> /// Ask the kernel which OS is installed, fail if it doesn't match the one in the file. /// </summary> public async Task <bool> IsSameOperatingSystemAccordingToKernel(FileValidator validator, CancellationToken cancellationToken) { Response <uint> osidResponse = await this.QueryOperatingSystemIdFromKernel(cancellationToken); if (osidResponse.Status != ResponseStatus.Success) { // The kernel seems broken. This shouldn't happen, but if it does, halt. this.logger.AddUserMessage("The kernel did not respond to operating system ID query."); return(false); } if (!validator.IsSameOperatingSystem(osidResponse.Value)) { return(false); } return(true); }
/// <summary> /// Write changes to the PCM's flash memory. /// </summary> private async void write_BackgroundThread(WriteType writeType) { using (new AwayMode()) { try { this.currentWriteType = writeType; if (this.Vehicle == null) { // This shouldn't be possible - it would mean the buttons // were enabled when they shouldn't be. return; } this.cancellationTokenSource = new CancellationTokenSource(); string path = null; this.Invoke((MethodInvoker) delegate() { this.DisableUserInput(); this.cancelButton.Enabled = true; path = this.ShowOpenDialog(); }); if (path == null) { return; } this.AddUserMessage(path); byte[] image; using (Stream stream = File.OpenRead(path)) { image = new byte[stream.Length]; int bytesRead = await stream.ReadAsync(image, 0, (int)stream.Length); if (bytesRead != stream.Length) { // If this happens too much, we should try looping rather than reading the whole file in one shot. this.AddUserMessage("Unable to load file."); return; } } // Sanity checks. FileValidator validator = new FileValidator(image, this); if (!validator.IsValid()) { this.AddUserMessage("This file is corrupt. It would render your PCM unusable."); return; } UInt32 kernelVersion = 0; bool needUnlock; int keyAlgorithm = 1; UInt32 pcmOperatingSystemId = 0; bool needToCheckOperatingSystem = writeType != WriteType.Full; this.AddUserMessage("Requesting operating system ID..."); Response <uint> osidResponse = await this.Vehicle.QueryOperatingSystemId(this.cancellationTokenSource.Token); if (osidResponse.Status == ResponseStatus.Success) { pcmOperatingSystemId = osidResponse.Value; PcmInfo info = new PcmInfo(pcmOperatingSystemId); keyAlgorithm = info.KeyAlgorithm; needUnlock = true; if (needToCheckOperatingSystem && !validator.IsSameOperatingSystem(pcmOperatingSystemId)) { this.AddUserMessage("Flashing this file could render your PCM unusable."); return; } needToCheckOperatingSystem = false; } else { if (this.cancellationTokenSource.Token.IsCancellationRequested) { return; } this.AddUserMessage("Operating system request failed, checking for a live kernel..."); kernelVersion = await this.Vehicle.GetKernelVersion(); if (kernelVersion == 0) { this.AddUserMessage("Checking for recovery mode..."); bool recoveryMode = await this.Vehicle.IsInRecoveryMode(); if (recoveryMode) { this.AddUserMessage("PCM is in recovery mode."); needUnlock = true; } else { this.AddUserMessage("PCM is not responding to OSID, kernel version, or recovery mode checks."); this.AddUserMessage("Unlock may not work, but we'll try..."); needUnlock = true; } } else { needUnlock = false; this.AddUserMessage("Kernel version: " + kernelVersion.ToString("X8")); this.AddUserMessage("Asking kernel for the PCM's operating system ID..."); if (needToCheckOperatingSystem && !await this.Vehicle.IsSameOperatingSystemAccordingToKernel(validator, this.cancellationTokenSource.Token)) { this.AddUserMessage("Flashing this file could render your PCM unusable."); return; } needToCheckOperatingSystem = false; } } await this.Vehicle.SuppressChatter(); if (needUnlock) { bool unlocked = await this.Vehicle.UnlockEcu(keyAlgorithm); if (!unlocked) { this.AddUserMessage("Unlock was not successful."); return; } this.AddUserMessage("Unlock succeeded."); } DateTime start = DateTime.Now; CKernelWriter writer = new CKernelWriter( this.Vehicle, new Protocol(), this); await writer.Write( image, writeType, kernelVersion, validator, needToCheckOperatingSystem, this.cancellationTokenSource.Token); this.AddUserMessage("Elapsed time " + DateTime.Now.Subtract(start)); } catch (IOException exception) { this.AddUserMessage(exception.ToString()); } finally { this.currentWriteType = WriteType.None; this.Invoke((MethodInvoker) delegate() { this.EnableUserInput(); this.cancelButton.Enabled = false; }); // The token / token-source can only be cancelled once, so we need to make sure they won't be re-used. this.cancellationTokenSource = null; } } }