From b2704d2d8fa000d236e849e6744df042fa966e5e Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 8 Feb 2024 02:38:40 -0500 Subject: [PATCH 001/112] connect qualcomusb --- qdl_utils/qdl.js | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 qdl_utils/qdl.js diff --git a/qdl_utils/qdl.js b/qdl_utils/qdl.js new file mode 100644 index 0000000..94c86cc --- /dev/null +++ b/qdl_utils/qdl.js @@ -0,0 +1,97 @@ +const vendorID = 0x05c6; +const productID = 0x9008; +const QDL_USB_CLASS = 0xff; + +export class qdlDevice { + device; + epIn; + epOut; + + _registeredUsbListeners; + + constructor() { + this.device = null; + this.epIn = null; + this.epOut = null; + this._registeredUsbListeners = null; + } + + async _validateAndConnectDevice() { + let ife = this.device?.configurations[0].interfaces[0].alternates[0]; + if (ife.endpoints.length !== 2) { + console.log("Interface has wrong number of endpoints"); + } + + this.epIn = null; + this.epOut = null; + + for (let endpoint of ife.endpoints) { + console.log("Checking endpoint:", endpoint); + if (endpoint.type !== "bulk") { + console.log("Interface endpoint is not bulk"); + } + if (endpoint.direction === "in") { + if (this.epIn === null) { + this.epIn = endpoint.endpointNumber; + } else { + console.log("Interface has multiple IN endpoints"); + } + } else if (endpoint.direction === "out") { + if (this.epOut === null) { + this.epOut = endpoint.endpointNumber; + } else { + console.log("Interface has multiple OUT endpoints"); + } + } + } + console.log("Endpoints: in =", this.epIn, ", out =", this.epOut); + + try { + await this.device?.open(); + // Opportunistically reset to fix issues on some platforms + try { + await this.device?.reset(); + } catch (error) { + /* Failed = doesn't support reset */ + } + await this.device?.selectConfiguration(1); + await this.device?.claimInterface(0); // fastboot + } catch (error) { + throw error; + } + } + + + async connect() { + console.log("In hello") + let devices = await navigator.usb.getDevices(); + console.log("Found these USB devices:", devices); + + this.device = await navigator.usb.requestDevice({ + filters: [ + { + vendorID : vendorID, + productID : productID, + calssCode : QDL_USB_CLASS, + }, + ], + }); + console.log("USing USB device:", this.device); + + if (!this._registeredUsbListeners){ + navigator.usb.addEventListener("connect", (event) =>{ + console.log("USB device connect:", event.device); + this.device = event.device; + + try { + await.this._validateAndConnectDevice(); + } catch (error) { + console.log("Error while connecting to the device") + } + }); + + this._registeredUsbListeners = true; + } + await this._validateAndConnectDevice(); + } +} \ No newline at end of file From 5fea12a5b72eab3449ce7c184c385395f836866a Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 10 Feb 2024 02:06:15 -0500 Subject: [PATCH 002/112] finish read write --- qdl_utils/qdl.js | 91 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 69 insertions(+), 22 deletions(-) diff --git a/qdl_utils/qdl.js b/qdl_utils/qdl.js index 94c86cc..a9caf71 100644 --- a/qdl_utils/qdl.js +++ b/qdl_utils/qdl.js @@ -2,6 +2,15 @@ const vendorID = 0x05c6; const productID = 0x9008; const QDL_USB_CLASS = 0xff; +// TODO: waitforconnect to check for valid device + +export class UsbError extends Error { + constructor(message) { + super(message); + this.name = "UsbError"; + } +} + export class qdlDevice { device; epIn; @@ -19,30 +28,30 @@ export class qdlDevice { async _validateAndConnectDevice() { let ife = this.device?.configurations[0].interfaces[0].alternates[0]; if (ife.endpoints.length !== 2) { - console.log("Interface has wrong number of endpoints"); + throw new UsbError("Attempted to connect to null device"); } this.epIn = null; this.epOut = null; for (let endpoint of ife.endpoints) { - console.log("Checking endpoint:", endpoint); - if (endpoint.type !== "bulk") { - console.log("Interface endpoint is not bulk"); + console.log("Checking endpoint:", endpoint); + if (endpoint.type !== "bulk") { + throw new UsbError("Interface endpoint is not bulk"); + } + if (endpoint.direction === "in") { + if (this.epIn === null) { + this.epIn = endpoint; + } else { + throw new UsbError("Interface has multiple IN endpoints"); } - if (endpoint.direction === "in") { - if (this.epIn === null) { - this.epIn = endpoint.endpointNumber; - } else { - console.log("Interface has multiple IN endpoints"); - } - } else if (endpoint.direction === "out") { - if (this.epOut === null) { - this.epOut = endpoint.endpointNumber; - } else { - console.log("Interface has multiple OUT endpoints"); - } + } else if (endpoint.direction === "out") { + if (this.epOut === null) { + this.epOut = endpoint; + } else { + throw new UsbError("Interface has multiple OUT endpoints"); } + } } console.log("Endpoints: in =", this.epIn, ", out =", this.epOut); @@ -55,36 +64,36 @@ export class qdlDevice { /* Failed = doesn't support reset */ } await this.device?.selectConfiguration(1); - await this.device?.claimInterface(0); // fastboot + await this.device?.claimInterface(0); } catch (error) { throw error; } } - async connect() { - console.log("In hello") + console.log("Trying to connect Qualcomm device") let devices = await navigator.usb.getDevices(); console.log("Found these USB devices:", devices); + //console.log("USing USB device:", this.device); this.device = await navigator.usb.requestDevice({ filters: [ { vendorID : vendorID, productID : productID, - calssCode : QDL_USB_CLASS, + classCode : QDL_USB_CLASS, }, ], }); console.log("USing USB device:", this.device); if (!this._registeredUsbListeners){ - navigator.usb.addEventListener("connect", (event) =>{ + navigator.usb.addEventListener("connect", async (event) =>{ console.log("USB device connect:", event.device); this.device = event.device; try { - await.this._validateAndConnectDevice(); + await this._validateAndConnectDevice(); } catch (error) { console.log("Error while connecting to the device") } @@ -94,4 +103,42 @@ export class qdlDevice { } await this._validateAndConnectDevice(); } + + async _usbRead(resplen = null){ + let respData = { text : "" }; + + if (!(resplen === null)) { resplen = this.epIn.packetSize; } + + while (respData.text.length < resplen) { + try { + let respPacket = await this.device?.transferIn(this.epIn.endpointNumber, resplen); + respData.text += respPacket.data; + } catch (error) { + if (error.includes("timed out")) { + console.error("Timed out"); + return new TextDecoder().endcode(""); + } else if (error.includes("Overflow")) { + console.error("USB Overflow"); + return new TextDecoder().endcode(""); + } + } + } + return respData; + } + + async _usbWrite(cmd, pktSize=null) { + if (!(pktSize === null)) { pktSize = this.epOut.packetSize; } + let cmdPacket = new TextDecoder().encode(cmd); + let offset = 0; + while (offset < cmdPacket.length){ + try { + await this.device.transferOut(this.epOut.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + offset += pktSize; + } catch (error) { + console.error(error); + return false; + } + } + return true; + } } \ No newline at end of file From 4e874ce64a5a6238ee7ba9cf4346bc4659537620 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 11 Feb 2024 17:15:00 -0500 Subject: [PATCH 003/112] sahara setup --- QDL/detach_driver.py | 58 +++++++++++++++++++++++++++++++ QDL/qdl.js | 35 +++++++++++++++++++ QDL/qualcommConfig.js | 3 ++ QDL/sahara.js | 48 +++++++++++++++++++++++++ QDL/saharaDefs.js | 56 +++++++++++++++++++++++++++++ qdl_utils/qdl.js => QDL/usblib.js | 47 +++++++++++++++++-------- 6 files changed, 232 insertions(+), 15 deletions(-) create mode 100644 QDL/detach_driver.py create mode 100644 QDL/qdl.js create mode 100644 QDL/qualcommConfig.js create mode 100644 QDL/sahara.js create mode 100644 QDL/saharaDefs.js rename qdl_utils/qdl.js => QDL/usblib.js (74%) diff --git a/QDL/detach_driver.py b/QDL/detach_driver.py new file mode 100644 index 0000000..000b9f7 --- /dev/null +++ b/QDL/detach_driver.py @@ -0,0 +1,58 @@ +import sys +import usb.core +import usb.util +import usb.backend.libusb0 +import usb.backend.libusb1 +from ctypes import c_void_p, c_int + +class usb_class: + def __init__(self, portconfig=None): + self.portconfig = portconfig + self.device = None + if sys.platform.startswith('freebsd') or sys.platform.startswith('linux') or sys.platform.startswith('darwin'): + self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.so") + else: + print("Only support Unix-based machine") + sys.exit(1) + if self.backend is not None: + try: + self.backend.lib.libusb_set_option.argtypes = [c_void_p, c_int] + self.backend.lib.libusb_set_option(self.backend.ctx, 1) + except: + self.backend = None + + def detach_driver(self): + devices = usb.core.find(find_all=True, backend=self.backend) + for d in devices: + for usbid in self.portconfig: + if d.idProduct == usbid[1] and d.idVendor == usbid[0]: + self.device = d + break + if self.device is not None: + break + + if self.device is None: + print("Couldn't detect the device. Is it connected ?") + return False + + try: + self.configuration = self.device.get_active_configuration() + except usb.core.USBError as e: + if e.strerror == "Configuration not set": + self.device.set_configuration() + self.configuration = self.device.get_active_configuration() + if e.errno == 13: + self.backend = usb.backend.libusb0.get_backend() + self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid, backend=self.backend) + try: + if self.device.is_kernel_driver_active(0): + print("Detaching kernel driver...") + self.device.detach_kernel_driver(0) + print("Finish detaching kernel driver") + except Exception as err: + print("No kernel driver supported: " + str(err)) + return False + +if __name__ == "__main__": + cdc = usb_class([[0x05c6, 0x9008, -1]]) + cdc.detach_driver() \ No newline at end of file diff --git a/QDL/qdl.js b/QDL/qdl.js new file mode 100644 index 0000000..786a607 --- /dev/null +++ b/QDL/qdl.js @@ -0,0 +1,35 @@ +import { usbClass } from "./usblib" +import { Sahara } from "./sahara" + + +export class qdlDevice { + cdc; + sahara; + + constructor() { + this.cdc = new usbClass(); + this.sahara = new Sahara(this.cdc); + } + + async doconnect() { + while (!this.cdc.connected){ + await this.cdc?.connect(); + if (this.cdc.connected){ + console.log("Device detected"); + try { + let resp = await this.sahara?.connect(); + console.log("finish connecting sahara"); + if (resp.hasOwnProperty("mode")){ + let mode = resp["mode"]; + console.log("Mode detected:", mode); + return resp; + } + } catch (error) { + console.error(error); + process.exit(1); + } + } + } + return {"mode" : "error"}; + } +} \ No newline at end of file diff --git a/QDL/qualcommConfig.js b/QDL/qualcommConfig.js new file mode 100644 index 0000000..bfed177 --- /dev/null +++ b/QDL/qualcommConfig.js @@ -0,0 +1,3 @@ +export const msmids = { + 0x05F0E1: "MSM8996Pro" // SnapDragon 821, MSM8996SG +} \ No newline at end of file diff --git a/QDL/sahara.js b/QDL/sahara.js new file mode 100644 index 0000000..f9d9647 --- /dev/null +++ b/QDL/sahara.js @@ -0,0 +1,48 @@ +import { CommandHandler, cmd_t } from "./saharaDefs" + +export class Sahara { + cdc; + ch; // CommandHandler + pktSize; + version; + + constructor(cdc) { + this.cdc = cdc; + this.pktSize = null; + this.version = null; + this.ch = new CommandHandler(); + } + + async connect() { + try { + let v = await this.cdc?._usbRead(0xC * 0x4); + let v_text = new TextDecoder().decode(v); + console.log("v_text:", v_text); + if (v.length > 1){ + if (v[0] === 0x01){ + let pkt = this.ch.pkt_cmd_hdr(v); + if (pkt.cmd == cmd_t.SAHARA_HELLO_REQ) { + let rsp = this.ch.pkt_hello_req(v); + this.pktSize = rsp.cmd_packet_length; + this.version = rsp.version; + console.log("Protocol version: ${rsp.version}, Version supported: ${rsp.version_supported}") + return { "mode" : "sahara", "cmd" : cmd_t.SAHARA_HELLO_REQ, "data" : rsp }; + } else if (v_text.includes("") + this.cdc._usbwrite(data); + let resp = this.cdc._usbRead(); + let resp_text = new TextDecoder().decode(resp); + if (resp_text.includes("{ console.log("USB device connect:", event.device); this.device = event.device; @@ -95,7 +104,7 @@ export class qdlDevice { try { await this._validateAndConnectDevice(); } catch (error) { - console.log("Error while connecting to the device") + console.log("Error while connecting to the device"); } }); @@ -105,40 +114,48 @@ export class qdlDevice { } async _usbRead(resplen = null){ - let respData = { text : "" }; + let respData = { text : "", }; - if (!(resplen === null)) { resplen = this.epIn.packetSize; } + if ((resplen === null)) { resplen = this.epIn.packetSize; } while (respData.text.length < resplen) { try { - let respPacket = await this.device?.transferIn(this.epIn.endpointNumber, resplen); - respData.text += respPacket.data; + console.log("Transferring..."); + let respPacket = await this.device?.transferIn(this.epIn?.endpointNumber, resplen); + console.log("get respPacket"); + let response = new TextDecoder().decode(respPacket.data); + console.log("get response"); + respData.text += response; + console.log("added response"); } catch (error) { if (error.includes("timed out")) { console.error("Timed out"); - return new TextDecoder().endcode(""); + return new TextEncoder().endcode(""); } else if (error.includes("Overflow")) { console.error("USB Overflow"); - return new TextDecoder().endcode(""); + return new TextEncoder().endcode(""); } } } - return respData; + return new TextEncoder().encode(respData); } async _usbWrite(cmd, pktSize=null) { - if (!(pktSize === null)) { pktSize = this.epOut.packetSize; } - let cmdPacket = new TextDecoder().encode(cmd); + if (!(pktSize === null)) { pktSize = this.epOut?.packetSize; } + let cmdPacket = new TextEncoder().encode(cmd); let offset = 0; while (offset < cmdPacket.length){ + console.log("Get in in while loop in write") try { await this.device.transferOut(this.epOut.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); offset += pktSize; } catch (error) { console.error(error); - return false; + return new TextEncoder().encode(""); } } + //return true; return true; + //return this._usbRead() } } \ No newline at end of file From 210a35962e5454bd8e4d5800e4295e549e1f33ba Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 11 Feb 2024 23:30:23 -0500 Subject: [PATCH 004/112] js is painful --- QDL/sahara.js | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++- QDL/usblib.js | 17 ++++++------- QDL/utils.js | 30 +++++++++++++++++++++++ 3 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 QDL/utils.js diff --git a/QDL/sahara.js b/QDL/sahara.js index f9d9647..dfb4aee 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -1,4 +1,5 @@ -import { CommandHandler, cmd_t } from "./saharaDefs" +import { CommandHandler, cmd_t, sahara_mode_t } from "./saharaDefs" +import { packGenerator } from "./utils"; export class Sahara { cdc; @@ -45,4 +46,69 @@ export class Sahara { return { "mode" : "error" }; } } + + async enterCommandMode(version=2) { + console.log("In enterCommandMode"); + if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND, version=version)){ + console.log("cmdHello() in enterCommandMode failed"); + return false; + } + console.log("Finish cmdHello") + let res = await this.getResponse(); + if (res.hasOwnProperty("cmd")){ + if (res["cmd"] === cmd_t.SAHARA_END_TRANSFER){ + if (res.hasOwnProperty("data")){ + //let pkt = res["data"]; + return false; + } + } else if (res["cmd"] === cmd_t.SAHARA_CMD_READY){ + return true; + } + } + return false; + } + + async getResponse() { + try { + let data = await this.cdc?._usbRead(); + let data_text = new TextDecoder().decode(data); + if (data_text.includes("")) { + return {}; + } else if (data_text.includes(" Date: Wed, 14 Feb 2024 04:23:10 -0500 Subject: [PATCH 005/112] finish sahara --- QDL/detach_driver.py | 2 +- QDL/qdl.js | 5 +- QDL/qualcommConfig.js | 2 +- QDL/sahara.js | 117 +++++++++++++++++++++++++++++++++++++++--- QDL/saharaDefs.js | 113 ++++++++++++++++++++++++++++++++++++++-- QDL/usblib.js | 50 ++++++++---------- QDL/utils.js | 35 +++++++++---- 7 files changed, 269 insertions(+), 55 deletions(-) diff --git a/QDL/detach_driver.py b/QDL/detach_driver.py index 000b9f7..b0ff718 100644 --- a/QDL/detach_driver.py +++ b/QDL/detach_driver.py @@ -55,4 +55,4 @@ def detach_driver(self): if __name__ == "__main__": cdc = usb_class([[0x05c6, 0x9008, -1]]) - cdc.detach_driver() \ No newline at end of file + cdc.detach_driver() diff --git a/QDL/qdl.js b/QDL/qdl.js index 786a607..ae295b9 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -1,7 +1,6 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" - export class qdlDevice { cdc; sahara; @@ -18,7 +17,6 @@ export class qdlDevice { console.log("Device detected"); try { let resp = await this.sahara?.connect(); - console.log("finish connecting sahara"); if (resp.hasOwnProperty("mode")){ let mode = resp["mode"]; console.log("Mode detected:", mode); @@ -26,10 +24,9 @@ export class qdlDevice { } } catch (error) { console.error(error); - process.exit(1); } } } return {"mode" : "error"}; } -} \ No newline at end of file +} diff --git a/QDL/qualcommConfig.js b/QDL/qualcommConfig.js index bfed177..547318c 100644 --- a/QDL/qualcommConfig.js +++ b/QDL/qualcommConfig.js @@ -1,3 +1,3 @@ export const msmids = { 0x05F0E1: "MSM8996Pro" // SnapDragon 821, MSM8996SG -} \ No newline at end of file +} diff --git a/QDL/sahara.js b/QDL/sahara.js index dfb4aee..f54e265 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -1,33 +1,38 @@ -import { CommandHandler, cmd_t, sahara_mode_t } from "./saharaDefs" -import { packGenerator } from "./utils"; +import { CommandHandler, cmd_t, sahara_mode_t, status_t } from "./saharaDefs" +import { concatUint8Array, packGenerator } from "./utils"; export class Sahara { cdc; ch; // CommandHandler pktSize; version; + programmer; + id; + mode; constructor(cdc) { this.cdc = cdc; this.pktSize = null; this.version = null; this.ch = new CommandHandler(); + this.programmer = ""; + this.id = null; + this.mode = ""; } async connect() { try { let v = await this.cdc?._usbRead(0xC * 0x4); - let v_text = new TextDecoder().decode(v); - console.log("v_text:", v_text); + let v_text = new TextDecoder("utf-8").decode(v); if (v.length > 1){ - if (v[0] === 0x01){ + if (v[0] == 0x01){ let pkt = this.ch.pkt_cmd_hdr(v); if (pkt.cmd == cmd_t.SAHARA_HELLO_REQ) { let rsp = this.ch.pkt_hello_req(v); this.pktSize = rsp.cmd_packet_length; this.version = rsp.version; - console.log("Protocol version: ${rsp.version}, Version supported: ${rsp.version_supported}") return { "mode" : "sahara", "cmd" : cmd_t.SAHARA_HELLO_REQ, "data" : rsp }; + // TODO: probably don't need from here downward till end of this func } else if (v_text.includes("= 0 || done){ + let resp = this.getResponse(); + if (resp.hasOwnProperty("cmd")){ + let cmd = resp["cmd"]; + } else { + console.error("Timeout while uploading loader. Wrong loader?"); + return "" + } + //if (cmd == cmd_t.SAHARA_DONE_REQ){ + // if (self.cmdDone()){ + // return "" + // } + //} + // TODO: Probably not necessary + if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)){ + if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) + console.log("64-bit mode detected"); + let pkt = resp["data"]; + this.id = pkt.image_id; + if (this.id >= 0xC){ + this.mode = "firehose"; + if (loop == 0) + console.log("Firehose mode detected, uploading..."); + } else { + console.error("Unknown sahara id"); + return "error"; + } + loop += 1; + let dataOffset = pkt.dataOffset; + let dataLen = pkt.data_len; + if (dataOffset + dataLen > programmer.length){ + let fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); + programmer = concatUint8Array([programmer, fillerArray]); + } + let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array + this.cdc?._usbWrite(dataToSend); + datalen -= dataLen; + } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { + let pkt = resp["data"]; + if (pkt.image_txt_status == status_t.SAHARA_STATUS_SUCCESS){ + if (this.cmdDone()){ + console.log("Loader successfully uploaded"); + } else { + console.error("Error on uploading loader."); + } + return this.mode; + } + } + } + } catch (error) { + console.error(error); + } + return this.mode; + } + + async loadProgrammerFromLocal(path){} + + async cmdDone(){ + if (await this.cdc._usbWrite(packGenerator([cmd_t.SAHARA_DONE_REQ], 0x8))){ + let res = this.getResponse() + for (let i = 0; i < 10; i++) + continue; + if (res.hasOwnProperty("cmd")){ + let cmd = res["cmd"]; + if (cmd == cmd_t.SAHARA_DONE_RSP){ + return true + } else if (cmd == cmd_t.SAHARA_END_TRANSFER){ + if (res.hasOwnProperty("data")) { + let pkt = res["data"]; + if (pkt.iamge_txt_status == status_t.SAHARA_NAK_INVALID_CMD){ + console.error("Invalid transfer command received"); + return false; + } + } + } else { + console.error("received invalid resposne"); + } + } + } + return false; + } + async enterCommandMode(version=2) { console.log("In enterCommandMode"); if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND, version=version)){ @@ -92,7 +193,7 @@ export class Sahara { return {"cmd": pkt.cmd, "data": None }; } return {}; - } catch (erro) { + } catch (error) { console.error(error); return {}; } @@ -111,4 +212,4 @@ export class Sahara { return false; } } -} \ No newline at end of file +} diff --git a/QDL/saharaDefs.js b/QDL/saharaDefs.js index 154fd0f..0c84324 100644 --- a/QDL/saharaDefs.js +++ b/QDL/saharaDefs.js @@ -22,13 +22,65 @@ export const cmd_t = { //SAHARA_RESET_STATE_MACHINE_ID : 0x13 } +export const sahara_mode_t = { + SAHARA_MODE_IMAGE_TX_PENDING : 0x0, + //SAHARA_MODE_IMAGE_TX_COMPLETE = 0x1, + //SAHARA_MODE_MEMORY_DEBUG = 0x2, + SAHARA_MODE_COMMAND : 0x3 +} + +export const status_t = { + SAHARA_STATUS_SUCCESS : 0x00, // Invalid command received in current state + SAHARA_NAK_INVALID_CMD : 0x01, // Protocol mismatch between host and targe + SAHARA_NAK_PROTOCOL_MISMATCH : 0x02, // Invalid target protocol version + SAHARA_NAK_INVALID_TARGET_PROTOCOL : 0x03, // Invalid host protocol version + SAHARA_NAK_INVALID_HOST_PROTOCOL : 0x04, // Invalid packet size received + SAHARA_NAK_INVALID_PACKET_SIZE : 0x05, // Unexpected image ID received + SAHARA_NAK_UNEXPECTED_IMAGE_ID : 0x06, // Invalid image header size received + SAHARA_NAK_INVALID_HEADER_SIZE : 0x07, // Invalid image data size received + SAHARA_NAK_INVALID_DATA_SIZE : 0x08, // Invalid image type received + SAHARA_NAK_INVALID_IMAGE_TYPE : 0x09, // Invalid tranmission length + SAHARA_NAK_INVALID_TX_LENGTH : 0x0A, // Invalid reception length + SAHARA_NAK_INVALID_RX_LENGTH : 0x0B, // General transmission or reception error + SAHARA_NAK_GENERAL_TX_RX_ERROR : 0x0C, // Error while transmitting READ_DATA packet + SAHARA_NAK_READ_DATA_ERROR : 0x0D, // Cannot receive specified number of program headers + SAHARA_NAK_UNSUPPORTED_NUM_PHDRS : 0x0E, // Invalid data length received for program headers + SAHARA_NAK_INVALID_PDHR_SIZE : 0x0F, // Multiple shared segments found in ELF image + SAHARA_NAK_MULTIPLE_SHARED_SEG : 0x10, // Uninitialized program header location + SAHARA_NAK_UNINIT_PHDR_LOC : 0x11, // Invalid destination address + SAHARA_NAK_INVALID_DEST_ADDR : 0x12, // Invalid data size received in image header + SAHARA_NAK_INVALID_IMG_HDR_DATA_SIZE : 0x13, // Invalid ELF header received + SAHARA_NAK_INVALID_ELF_HDR : 0x14, // Unknown host error received in HELLO_RESP + SAHARA_NAK_UNKNOWN_HOST_ERROR : 0x15, // Timeout while receiving data + SAHARA_NAK_TIMEOUT_RX : 0x16, // Timeout while transmitting data + SAHARA_NAK_TIMEOUT_TX : 0x17, // Invalid mode received from host + SAHARA_NAK_INVALID_HOST_MODE : 0x18, // Invalid memory read access + SAHARA_NAK_INVALID_MEMORY_READ : 0x19, // Host cannot handle read data size requested + SAHARA_NAK_INVALID_DATA_SIZE_REQUEST : 0x1A, // Memory debug not supported + SAHARA_NAK_MEMORY_DEBUG_NOT_SUPPORTED : 0x1B, // Invalid mode switch + SAHARA_NAK_INVALID_MODE_SWITCH : 0x1C, // Failed to execute command + SAHARA_NAK_CMD_EXEC_FAILURE : 0x1D, // Invalid parameter passed to command execution + SAHARA_NAK_EXEC_CMD_INVALID_PARAM : 0x1E, // Unsupported client command received + SAHARA_NAK_EXEC_CMD_UNSUPPORTED : 0x1F, // Invalid client command received for data response + SAHARA_NAK_EXEC_DATA_INVALID_CLIENT_CMD : 0x20, // Failed to authenticate hash table + SAHARA_NAK_HASH_TABLE_AUTH_FAILURE : 0x21, // Failed to verify hash for a given segment of ELF image + SAHARA_NAK_HASH_VERIFICATION_FAILURE : 0x22, // Failed to find hash table in ELF image + SAHARA_NAK_HASH_TABLE_NOT_FOUND : 0x23, // Target failed to initialize + SAHARA_NAK_TARGET_INIT_FAILURE : 0x24, // Failed to authenticate generic image + SAHARA_NAK_IMAGE_AUTH_FAILURE : 0x25, // Invalid ELF hash table size. Too bit or small. + SAHARA_NAK_INVALID_IMG_HASH_TABLE_SIZE : 0x26, + SAHARA_NAK_ENUMERATION_FAILURE : 0x27, + SAHARA_NAK_HW_BULK_TRANSFER_ERROR : 0x28, + SAHARA_NAK_MAX_CODE : 0x7FFFFFFF // To ensure 32-bits wide */ +} + export class CommandHandler { pkt_cmd_hdr(data) { if (data.length < 2*4) { console.error("DataError!") process.exit(1) } - st = structHelper_io(data); + let st = new structHelper_io(data); return { cmd : st.dword(0), len : st.dword(4) } } @@ -37,7 +89,7 @@ export class CommandHandler { console.error("DataError!") process.exit(1) } - st = structHelper_io(data); + let st = new structHelper_io(data); return { cmd : st.dword(0), len : st.dword(4), @@ -53,4 +105,59 @@ export class CommandHandler { reserved6 : st.dword(44), } } -} \ No newline at end of file + pkt_image_end(data) { + if (data.length<0x4 * 0x4){ + console.error("ERROR"); + process.exit(1); + } + let st = new structHelper_io(data); + return { + cmd : st.dword(0), + len : st.dword(4), + image_id : st.dword(8), + image_tx_status : st.dword(12), + } + } + + pkt_done(data) { + if (data.length <0x3 * 4) { + console.error("DataError"); + process.exit(1); + } + let st = new structHelper_io(data); + return { + cmd : st.dword(0), + len : st.dword(4), + image_tx_status : st.dword(8) + } + } + + pkt_read_data_64(data) { + if (data.length <0x8 + 0x3 * 0x8) { + console.error("DataError") + process.exit(1) + } + let st = new structHelper_io(data) + return { + cmd : st.dword(0), + len : st.dword(4), + image_id : st.qword(8), + data_offset : st.qword(16), + data_len : st.qword(24), + } + } + + pkt_execute_rsp_cmd(data) { + if (data.length <0x4 * 0x4) { + console.error("DataError"); + process.exit(1); + } + let st = new structHelper_io(data) + return { + cmd : st.dword(0), + len : st.dword(4), + client_cmd : st.dword(8), + data_len : st.dword(12), + } + } +} diff --git a/QDL/usblib.js b/QDL/usblib.js index 1bbbd13..dcb4f32 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -1,3 +1,5 @@ +import { concatUint8Array } from "./utils"; + const vendorID = 0x05c6; const productID = 0x9008; const QDL_USB_CLASS = 0xff; @@ -65,12 +67,6 @@ export class usbClass { try { await this.device?.open(); - // Opportunistically reset to fix issues on some platforms - try { - await this.device?.reset(); - } catch (error) { - /* Failed = doesn't support reset */ - } await this.device?.selectConfiguration(1); await this.device?.claimInterface(0); } catch (error) { @@ -112,49 +108,45 @@ export class usbClass { await this._validateAndConnectDevice(); } - async _usbRead(resplen = null){ - let respData = { text : "", }; - - if ((resplen === null)) { resplen = this.epIn.packetSize; } + async _usbRead(resplen=null){ + let respData = null; + let covered = 0; + if ((resplen === null)) + resplen = this.epIn.packetSize; - while (respData.text.length < resplen) { + while (covered < resplen) { try { console.log("Transferring In..."); let respPacket = await this.device?.transferIn(this.epIn?.endpointNumber, resplen); - console.log("get respPacket"); - let response = new TextDecoder().decode(respPacket.data); - console.log("get response"); - respData.text += response; - console.log("added response"); + respData = concatUint8Array([respData, new Uint8Array(respPacket.data.buffer)]); + if (respData !== null) + covered += respData.length; } catch (error) { - if (error.includes("timed out")) { - console.error("Timed out"); - return new TextEncoder().endcode(""); - } else if (error.includes("Overflow")) { - console.error("USB Overflow"); - return new TextEncoder().endcode(""); - } + console.error(error); } } - return new TextEncoder().encode(respData); + return respData; } async _usbWrite(cmdPacket, pktSize=null) { - if (!(pktSize === null)) { pktSize = this.epOut?.packetSize; } - //let cmdPacket = new TextEncoder().encode(cmd); let offset = 0; + if (pktSize === null) + if (cmdPacket.length > this.epOUt?.packetSize){ + pktSize = this.epOut?.packetSize; + } else { + pktSize = cmdPacket.length; + } + while (offset < cmdPacket.length){ try { console.log("Transferring Out...") - console.log(cmdPacket.slice(offset, offset+4)); await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); offset += pktSize; } catch (error) { console.error(error); - //return new TextEncoder().encode(""); return false; } } return true; } -} \ No newline at end of file +} diff --git a/QDL/utils.js b/QDL/utils.js index d0a5799..b1c47a0 100644 --- a/QDL/utils.js +++ b/QDL/utils.js @@ -6,17 +6,15 @@ export class structHelper_io { this.data = data; } - dword(idx_start) { - // TODO: check endianess - dat = new TextDecoder('utf-8').decode(data).substring(idx_start, idx_start + 4 - 1); - return dat; + dword(idx_start, littleEndian=true) { + let view = new DataView(this.data.slice(idx_start, idx_start+4).buffer, 0); + return view.getUint32(0, littleEndian); } - qword(idx_start) { - dat = new TextDecoder('utf-8').decode(data).substring(idx_start, idx_start + 8 - 1); - return dat; + qword(idx_start, littleEndian=true) { + let view = new DataView(this.data.slice(idx_start, idx_start+8).buffer, 0); + return view.getUint64(0, littleEndian); } - } export function packGenerator(elements, littleEndian=true) { @@ -27,4 +25,23 @@ export function packGenerator(elements, littleEndian=true) { view.setUint32(i*4, elements[i], littleEndian); } return new Uint8Array(view.buffer); -} \ No newline at end of file +} + +export function concatUint8Array(arrays){ + let length = 0; + arrays.forEach(item => { + if (item !== null) + length += item.length; + }); + + let concatArray = new Uint8Array(length); + let offset = 0; + arrays.forEach( item => { + if (item !== null) { + concatArray.set(item, offset); + offset += item.length; + } + }); + + return concatArray; +} From e19ca3ceb9909f82ba57829716e05dffbbc9ea56 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 16 Feb 2024 18:18:56 -0500 Subject: [PATCH 006/112] upload programmer --- QDL/qdl.js | 17 ++++- QDL/sahara.js | 197 ++++++++++++++++++++++++++++++-------------------- 2 files changed, 136 insertions(+), 78 deletions(-) diff --git a/QDL/qdl.js b/QDL/qdl.js index ae295b9..00090b1 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -29,4 +29,19 @@ export class qdlDevice { } return {"mode" : "error"}; } -} + + /** TODO: check for connected to sahara + * or mode = firehose then don't need to connect + */ + async reset() { + try { + let resp = await this.doconnect(); + let mode = resp["mode"]; + if (mode === "sahara") { + this.sahara?.uploadLoader(2); // version 2 + } + } catch (error) { + console.error(error); + } + } +} \ No newline at end of file diff --git a/QDL/sahara.js b/QDL/sahara.js index f54e265..4ff947f 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -15,7 +15,7 @@ export class Sahara { this.pktSize = null; this.version = null; this.ch = new CommandHandler(); - this.programmer = ""; + this.programmer = "0005f0e100000000_b155b8bf19297f47_fhprg_peek.bin"; this.id = null; this.mode = ""; } @@ -27,10 +27,13 @@ export class Sahara { if (v.length > 1){ if (v[0] == 0x01){ let pkt = this.ch.pkt_cmd_hdr(v); - if (pkt.cmd == cmd_t.SAHARA_HELLO_REQ) { + console.log("sahara cmd:", pkt.cmd); + if (pkt.cmd === cmd_t.SAHARA_HELLO_REQ) { let rsp = this.ch.pkt_hello_req(v); this.pktSize = rsp.cmd_packet_length; this.version = rsp.version; + console.log("pktSize:", this.pktSize); + console.log("version:", this.version); return { "mode" : "sahara", "cmd" : cmd_t.SAHARA_HELLO_REQ, "data" : rsp }; // TODO: probably don't need from here downward till end of this func } else if (v_text.includes("") this.cdc._usbwrite(data); - let resp = this.cdc._usbRead(); + let resp = await this.cdc._usbRead(); let resp_text = new TextDecoder().decode(resp); if (resp_text.includes("= 0 || done){ - let resp = this.getResponse(); - if (resp.hasOwnProperty("cmd")){ - let cmd = resp["cmd"]; - } else { - console.error("Timeout while uploading loader. Wrong loader?"); - return "" - } - //if (cmd == cmd_t.SAHARA_DONE_REQ){ - // if (self.cmdDone()){ - // return "" - // } - //} - // TODO: Probably not necessary - if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)){ - if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) - console.log("64-bit mode detected"); - let pkt = resp["data"]; - this.id = pkt.image_id; - if (this.id >= 0xC){ - this.mode = "firehose"; - if (loop == 0) - console.log("Firehose mode detected, uploading..."); - } else { - console.error("Unknown sahara id"); - return "error"; - } - loop += 1; - let dataOffset = pkt.dataOffset; - let dataLen = pkt.data_len; - if (dataOffset + dataLen > programmer.length){ - let fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); - programmer = concatUint8Array([programmer, fillerArray]); - } - let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array - this.cdc?._usbWrite(dataToSend); - datalen -= dataLen; - } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { - let pkt = resp["data"]; - if (pkt.image_txt_status == status_t.SAHARA_STATUS_SUCCESS){ - if (this.cmdDone()){ - console.log("Loader successfully uploaded"); - } else { - console.error("Error on uploading loader."); - } - return this.mode; - } - } + if (!(await this.enterCommandMode(version))) { + console.error("Failed to enter command mode in Sahara"); + return "error" + } else { + try { + await this.cmdModeSwitch(sahara_mode_t.SAHARA_MODE_COMMAND); + console.log("successfully switch mode in sahara to Command Mode"); + } catch (error) { + console.error(error); } - } catch (error) { - console.error(error); } - return this.mode; + console.log("Uploading Programmer..."); + const programmer = await this.loadProgrammerFromLocal(); + console.log("programmer", programmer); + //console.log("Uploading programmer..."); + //try { + // let programmer = await this.loadProgrammerFromLocal(); + //} catch (error) { + // console.error(error); + //} + //if (!this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version)) + // return ""; + //try { + // let datalen = programmer.length; + // let done = false; + // let loop = 0; + // while (datalen >= 0 || done){ + // let resp = this.getResponse(); + // if (resp.hasOwnProperty("cmd")){ + // let cmd = resp["cmd"]; + // } else { + // console.error("Timeout while uploading loader. Wrong loader?"); + // return "" + // } + // if (cmd == cmd_t.SAHARA_DONE_REQ){ + // if (self.cmdDone()){ + // return "" + // } + // } + // // TODO: Probably not necessary + // if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)){ + // if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) + // console.log("64-bit mode detected"); + // let pkt = resp["data"]; + // this.id = pkt.image_id; + // if (this.id >= 0xC){ + // this.mode = "firehose"; + // if (loop == 0) + // console.log("Firehose mode detected, uploading..."); + // } else { + // console.error("Unknown sahara id"); + // return "error"; + // } + // loop += 1; + // let dataOffset = pkt.dataOffset; + // let dataLen = pkt.data_len; + // if (dataOffset + dataLen > programmer.length){ + // let fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); + // programmer = concatUint8Array([programmer, fillerArray]); + // } + // let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array + // this.cdc?._usbWrite(dataToSend); + // datalen -= dataLen; + // } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { + // let pkt = resp["data"]; + // if (pkt.image_txt_status == status_t.SAHARA_STATUS_SUCCESS){ + // if (this.cmdDone()){ + // console.log("Loader successfully uploaded"); + // } else { + // console.error("Error on uploading loader."); + // } + // return this.mode; + // } + // } + // } + //} catch (error) { + // console.error(error); + //} + //return this.mode; } - async loadProgrammerFromLocal(path){} + async loadProgrammerFromLocal(){ + const [fileHandle] = await window.showOpenFilePicker(); + const blob = await fileHandle.getFile(); + return new Promise((resolve, reject) => { + let reader = new FileReader(); + reader.onload = () => { + resolve(reader.result); + }; + reader.onerror = () => { + reject(reader.error); + }; + reader.readAsArrayBuffer(blob); + }); + } async cmdDone(){ if (await this.cdc._usbWrite(packGenerator([cmd_t.SAHARA_DONE_REQ], 0x8))){ @@ -149,17 +180,13 @@ export class Sahara { } async enterCommandMode(version=2) { - console.log("In enterCommandMode"); - if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND, version=version)){ - console.log("cmdHello() in enterCommandMode failed"); + if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND)){ return false; } - console.log("Finish cmdHello") let res = await this.getResponse(); if (res.hasOwnProperty("cmd")){ if (res["cmd"] === cmd_t.SAHARA_END_TRANSFER){ if (res.hasOwnProperty("data")){ - //let pkt = res["data"]; return false; } } else if (res["cmd"] === cmd_t.SAHARA_CMD_READY){ @@ -171,11 +198,13 @@ export class Sahara { async getResponse() { try { + console.log('get in getResponse()') let data = await this.cdc?._usbRead(); - let data_text = new TextDecoder().decode(data); - if (data_text.includes("")) { + let data_text = new TextDecoder('utf-8').decode(data.data); + if (data.length == 0){ return {}; } else if (data_text.includes(" Date: Fri, 16 Feb 2024 18:47:11 -0500 Subject: [PATCH 007/112] fix usblib --- QDL/usblib.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/QDL/usblib.js b/QDL/usblib.js index dcb4f32..02d56d8 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -49,14 +49,12 @@ export class usbClass { } if (endpoint.direction === "in") { if (this.epIn === null) { - console.log("epIn", endpoint); this.epIn = endpoint; } else { throw new UsbError("Interface has multiple IN endpoints"); } } else if (endpoint.direction === "out") { if (this.epOut === null) { - console.log("epOut", endpoint); this.epOut = endpoint; } else { throw new UsbError("Interface has multiple OUT endpoints"); @@ -119,8 +117,8 @@ export class usbClass { console.log("Transferring In..."); let respPacket = await this.device?.transferIn(this.epIn?.endpointNumber, resplen); respData = concatUint8Array([respData, new Uint8Array(respPacket.data.buffer)]); - if (respData !== null) - covered += respData.length; + resplen = respData.length; + covered += respData.length; } catch (error) { console.error(error); } @@ -136,7 +134,6 @@ export class usbClass { } else { pktSize = cmdPacket.length; } - while (offset < cmdPacket.length){ try { console.log("Transferring Out...") From 0ea835face92541a62877eb5e4ae50c66c0bb65f Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 17 Feb 2024 00:57:48 -0500 Subject: [PATCH 008/112] load programmer --- QDL/qdl.js | 3 +- QDL/sahara.js | 160 +++++++++++++++++++++++++--------------------- QDL/saharaDefs.js | 10 +-- QDL/usblib.js | 4 +- QDL/utils.js | 2 +- 5 files changed, 99 insertions(+), 80 deletions(-) diff --git a/QDL/qdl.js b/QDL/qdl.js index 00090b1..ddba7e6 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -38,7 +38,8 @@ export class qdlDevice { let resp = await this.doconnect(); let mode = resp["mode"]; if (mode === "sahara") { - this.sahara?.uploadLoader(2); // version 2 + let mode = await this.sahara?.uploadLoader(2); // version 2 + console.log("mode from uploadloader:", mode); } } catch (error) { console.error(error); diff --git a/QDL/sahara.js b/QDL/sahara.js index 4ff947f..ec3c1b0 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -69,74 +69,86 @@ export class Sahara { console.error(error); } } + let connectResp = await this.connect(); + if ((connectResp["mode"] != "sahara")) { + console.log("failed reconnect sahara"); + return ""; + } console.log("Uploading Programmer..."); - const programmer = await this.loadProgrammerFromLocal(); - console.log("programmer", programmer); - //console.log("Uploading programmer..."); - //try { - // let programmer = await this.loadProgrammerFromLocal(); - //} catch (error) { - // console.error(error); - //} - //if (!this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version)) - // return ""; - //try { - // let datalen = programmer.length; - // let done = false; - // let loop = 0; - // while (datalen >= 0 || done){ - // let resp = this.getResponse(); - // if (resp.hasOwnProperty("cmd")){ - // let cmd = resp["cmd"]; - // } else { - // console.error("Timeout while uploading loader. Wrong loader?"); - // return "" - // } - // if (cmd == cmd_t.SAHARA_DONE_REQ){ - // if (self.cmdDone()){ - // return "" - // } - // } - // // TODO: Probably not necessary - // if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)){ - // if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) - // console.log("64-bit mode detected"); - // let pkt = resp["data"]; - // this.id = pkt.image_id; - // if (this.id >= 0xC){ - // this.mode = "firehose"; - // if (loop == 0) - // console.log("Firehose mode detected, uploading..."); - // } else { - // console.error("Unknown sahara id"); - // return "error"; - // } - // loop += 1; - // let dataOffset = pkt.dataOffset; - // let dataLen = pkt.data_len; - // if (dataOffset + dataLen > programmer.length){ - // let fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); - // programmer = concatUint8Array([programmer, fillerArray]); - // } - // let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array - // this.cdc?._usbWrite(dataToSend); - // datalen -= dataLen; - // } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { - // let pkt = resp["data"]; - // if (pkt.image_txt_status == status_t.SAHARA_STATUS_SUCCESS){ - // if (this.cmdDone()){ - // console.log("Loader successfully uploaded"); - // } else { - // console.error("Error on uploading loader."); - // } - // return this.mode; - // } - // } - // } - //} catch (error) { - // console.error(error); - //} - //return this.mode; + let programmer = new Uint8Array(await this.loadProgrammerFromLocal()); + console.log("programmer:", programmer); + if (!(await this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version))) { + return ""; + } + try { + let datalen = programmer.length; + let done = false; + let loop = 0; + while (datalen >= 0 || done){ + let resp = await this.getResponse(); + console.log("finish first getresponse"); + let cmd + if (resp.hasOwnProperty("cmd")){ + cmd = resp["cmd"]; + console.log("resp has cmd property:", cmd); + } else { + console.error("Timeout while uploading loader. Wrong loader?"); + return "" + } + if (cmd == cmd_t.SAHARA_DONE_REQ){ + if (self.cmdDone()){ + return "" + } + } + // TODO: Probably not necessary + if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)) { + if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) + console.log("64-bit mode detected"); + let pkt = resp["data"]; + this.id = pkt.image_id; + if (this.id >= 0xC){ + console.log("get in this.id >= 0xC"); + this.mode = "firehose"; + if (loop == 0) + console.log("Firehose mode detected, uploading..."); + } else { + console.error("Unknown sahara id"); + return "error"; + } + loop += 1; + let dataOffset = pkt.data_offset; + let dataLen = pkt.data_len; + console.log("dataLen:", dataLen); + console.log("compare:", dataOffset + dataLen); + console.log("programmer len:", programmer.length); + if (dataOffset + dataLen > programmer.length) { + console.log("in compare dataoffset and programmer len"); + const fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); + programmer = concatUint8Array([programmer, fillerArray]); + } + console.log("ready to slice programmer") + let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array + console.log("datatoSend:", dataToSend); + await this.cdc?._usbWrite(dataToSend); + datalen -= dataLen; + } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { + console.log("get into end transfer"); + let pkt = resp["data"]; + console.log("pkt.image_txt_status:", pkt.image_tx_status) + if (pkt.image_tx_status == status_t.SAHARA_STATUS_SUCCESS){ + if (await this.cmdDone()){ + console.log("Loader successfully uploaded"); + } else { + console.error("Error on uploading loader."); + } + return this.mode; + } + } + } + } catch (error) { + console.error(error); + } + return this.mode; } async loadProgrammerFromLocal(){ @@ -155,12 +167,15 @@ export class Sahara { } async cmdDone(){ - if (await this.cdc._usbWrite(packGenerator([cmd_t.SAHARA_DONE_REQ], 0x8))){ - let res = this.getResponse() - for (let i = 0; i < 10; i++) + const toSendData = packGenerator([cmd_t.SAHARA_DONE_REQ, 0x8]); + if (await this.cdc._usbWrite(toSendData)) { + console.log("successfully get in cmdDone after write"); + let res = await this.getResponse(); + for (let i = 0; i < 500; i += 1) continue; if (res.hasOwnProperty("cmd")){ let cmd = res["cmd"]; + console.log("cmd in getrsp:", cmd); if (cmd == cmd_t.SAHARA_DONE_RSP){ return true } else if (cmd == cmd_t.SAHARA_END_TRANSFER){ @@ -198,7 +213,6 @@ export class Sahara { async getResponse() { try { - console.log('get in getResponse()') let data = await this.cdc?._usbRead(); let data_text = new TextDecoder('utf-8').decode(data.data); if (data.length == 0){ @@ -207,6 +221,8 @@ export class Sahara { console.log("get in firehose?") return {"firehose" : "yes"}; } + console.log(data); + console.log(data.length); let pkt = this.ch.pkt_cmd_hdr(data); if (pkt.cmd === cmd_t.SAHARA_HELLO_REQ) { return { "cmd" : pkt.cmd, "data" : this.ch.pkt_hello_req(data) }; @@ -229,7 +245,7 @@ export class Sahara { } } - async cmdHello(mode, version_min=1, max_cmd_len=0, version=2) { + async cmdHello(mode, version=2, version_min=1, max_cmd_len=0) { let cmd = cmd_t.SAHARA_HELLO_RSP; let len = 0x30; const elements = [cmd, len, version, version_min, max_cmd_len, mode, 1, 2, 3, 4, 5, 6]; diff --git a/QDL/saharaDefs.js b/QDL/saharaDefs.js index 0c84324..d22255d 100644 --- a/QDL/saharaDefs.js +++ b/QDL/saharaDefs.js @@ -133,7 +133,7 @@ export class CommandHandler { } pkt_read_data_64(data) { - if (data.length <0x8 + 0x3 * 0x8) { + if (data.length < 0x8 + 0x3 * 0x8) { console.error("DataError") process.exit(1) } @@ -141,9 +141,9 @@ export class CommandHandler { return { cmd : st.dword(0), len : st.dword(4), - image_id : st.qword(8), - data_offset : st.qword(16), - data_len : st.qword(24), + image_id : Number(st.qword(8)), + data_offset : Number(st.qword(16)), + data_len : Number(st.qword(24)), } } @@ -160,4 +160,4 @@ export class CommandHandler { data_len : st.dword(12), } } -} +} \ No newline at end of file diff --git a/QDL/usblib.js b/QDL/usblib.js index 02d56d8..69c87a7 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -129,11 +129,13 @@ export class usbClass { async _usbWrite(cmdPacket, pktSize=null) { let offset = 0; if (pktSize === null) - if (cmdPacket.length > this.epOUt?.packetSize){ + if (cmdPacket.length > this.epOut?.packetSize){ pktSize = this.epOut?.packetSize; } else { pktSize = cmdPacket.length; } + console.log("default pktSize:", this.epOut?.packetSize); + console.log("pktSize in write:", pktSize); while (offset < cmdPacket.length){ try { console.log("Transferring Out...") diff --git a/QDL/utils.js b/QDL/utils.js index b1c47a0..2fb5058 100644 --- a/QDL/utils.js +++ b/QDL/utils.js @@ -13,7 +13,7 @@ export class structHelper_io { qword(idx_start, littleEndian=true) { let view = new DataView(this.data.slice(idx_start, idx_start+8).buffer, 0); - return view.getUint64(0, littleEndian); + return view.getBigUint64(0, littleEndian); } } From 99516035e0b76805e1daa00112ac7e44ce268ea6 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 17 Feb 2024 19:37:21 -0500 Subject: [PATCH 009/112] time out --- QDL/firehose.js | 124 +++++++++++++++++++++++++++++++++++++++++++++++ QDL/qdl.js | 4 ++ QDL/utils.js | 10 ++++ QDL/xmlParser.js | 50 +++++++++++++++++++ 4 files changed, 188 insertions(+) create mode 100644 QDL/firehose.js create mode 100644 QDL/xmlParser.js diff --git a/QDL/firehose.js b/QDL/firehose.js new file mode 100644 index 0000000..8771794 --- /dev/null +++ b/QDL/firehose.js @@ -0,0 +1,124 @@ +import { xmlParser } from "./xmlParser" +import { concatUint8Array, containsBytes, compareStringToBytes } from "./utils" + +class cfg { + + constructor() { + this.TargetName = ""; + this.Version = ""; + this.ZLPAwareHost = 1; + this.SkipStorageInit = 0; + this.SkipWrite = 0; + this.MaxPayloadSizeToTargetInBytes = 1048576; + this.MaxPayloadSizeFromTargetInBytes = 8192; + this.MaxXMLSizeInBytes = 4096; + this.bit64 = true; + this.total_blocks = 0; + this.num_physical = 0; + this.block_size = 0; + this.SECTOR_SIZE_IN_BYTES = 0; + this.MemoryName = "UFS"; + this.prod_name = "Unknown"; + this.maxlun = 99; + } +} + +export class Firehose { + cdc; + //xml; + cfg + + constructor(cdc) { + this.cdc = cdc; + this.xml = new xmlParser(); + this.cfg = new cfg(); + } + + async configure(lvl) { + if (this.cfg.SECTOR_SIZE_IN_BYTES == 0) + this.cfg.SECTOR_SIZE_IN_BYTES = 4096 + let connectCmd = `` + + `` + + `` + + // TODO: Transfer connectCmd to Uint8Array + console.log("writing config"); + let rsp = await this.xmlSend(connectCmd); + console.log("finish writing config") + return true; + } + + async xmlSend(data) { + let dataToSend = new TextEncoder().encode(data).slice(0, this.cfg.MaxXMLSizeInBytes); + await this.cdc?._usbWrite(dataToSend); + console.log("finish writing in xmlsend"); + let rData; // response data in bytes + let counter = 0; + let timeout = 0; + while (!(containsBytes(" timeout) + break; + } + console.log(new TextDecoder().decode(tmp)); + rData = concatUint8Array(rData, tmp); + console.log(new TextDecoder().decode(rData)); + } catch (error) { + console.error(error); + } + } + try { + const resp = this.xml.getReponse(rData); // input is Uint8Array + const status = this.getStatus(resp); + if (status !== null) { + if (containsBytes("log value=", rData)) { + //let log = this.xml.getLog(rData); + return { "resp" : status, "data" : rData, "log" : "" }; // TODO: getLog() + } + return { "resp" : status, "data" : rData }; + } + } catch (error) { + console.error(error); + } + return {"resp" : true, "data" : rData}; + } + + async cmdReset() { + let data = ""; + let val = await this.xmlSend(data); + if (val.resp) { + console.log("Reset succeeded"); + return true; + } else { + console.error("Reset failed"); + return false; + } + } + + getStatus(resp) { + if (resp.hasOwnProperty("value")) { + console.log("In getStatus") + let value = resp["value"]; + if (value == "ACK" || value == "true" ) { + console.log("IN value = ACK") + return true; + } else { + return false; + } + } + return true; + } +} diff --git a/QDL/qdl.js b/QDL/qdl.js index ddba7e6..8da799e 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -1,5 +1,6 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" +import { Firehose } from "./firehose" export class qdlDevice { cdc; @@ -8,6 +9,7 @@ export class qdlDevice { constructor() { this.cdc = new usbClass(); this.sahara = new Sahara(this.cdc); + this.firehose = new Firehose(this.cdc); } async doconnect() { @@ -41,6 +43,8 @@ export class qdlDevice { let mode = await this.sahara?.uploadLoader(2); // version 2 console.log("mode from uploadloader:", mode); } + await this.firehose?.configure(0); + await this.firehose?.cmdReset(); } catch (error) { console.error(error); } diff --git a/QDL/utils.js b/QDL/utils.js index 2fb5058..1e3e31e 100644 --- a/QDL/utils.js +++ b/QDL/utils.js @@ -45,3 +45,13 @@ export function concatUint8Array(arrays){ return concatArray; } + +export function containsBytes(subString, array) { + let tArray = new TextDecoder().decode(array); + return tArray.includes(subString); +} + +export function compareStringToBytes(compareString, array) { + let tArray = new TextDecoder().decode(array); + return compareString == tArray; +} diff --git a/QDL/xmlParser.js b/QDL/xmlParser.js new file mode 100644 index 0000000..10912d5 --- /dev/null +++ b/QDL/xmlParser.js @@ -0,0 +1,50 @@ +export class xmlParser { + getReponse(input) { + let tInput = new TextDecoder().decode(input); + let lines = tInput.split(" { + obj[attr.name] = attr.value; + return obj; + }, content); + } + } + return content; + } + + getLog(input) { + let tInput = new TextDecoder().decode(input); + let lines = tInput.split(" { + if (attr.name == "value") + obj.push(attr.value); + return obj; + }, data); + } + } + return data; + } +} From 78746e660584d7d57524a96dd3fd80ea60f80031 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 19 Feb 2024 04:13:39 -0500 Subject: [PATCH 010/112] can reset --- QDL/firehose.js | 23 +++++++---------------- QDL/sahara.js | 32 +++++--------------------------- QDL/usblib.js | 19 ++++++++++--------- QDL/utils.js | 2 ++ QDL/xmlParser.js | 2 +- 5 files changed, 25 insertions(+), 53 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index 8771794..4b885cd 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -1,5 +1,5 @@ import { xmlParser } from "./xmlParser" -import { concatUint8Array, containsBytes, compareStringToBytes } from "./utils" +import { concatUint8Array, containsBytes, compareStringToBytes, sleep } from "./utils" class cfg { @@ -49,33 +49,26 @@ export class Firehose { `` // TODO: Transfer connectCmd to Uint8Array - console.log("writing config"); - let rsp = await this.xmlSend(connectCmd); - console.log("finish writing config") + let rsp = await this.xmlSend(connectCmd, false); return true; } - async xmlSend(data) { + async xmlSend(data, wait=true) { let dataToSend = new TextEncoder().encode(data).slice(0, this.cfg.MaxXMLSizeInBytes); - await this.cdc?._usbWrite(dataToSend); - console.log("finish writing in xmlsend"); - let rData; // response data in bytes + await this.cdc?._usbWrite(dataToSend, null, wait); + let rData = new Uint8Array(); // response data in bytes let counter = 0; let timeout = 0; while (!(containsBytes(" timeout) break; } - console.log(new TextDecoder().decode(tmp)); - rData = concatUint8Array(rData, tmp); - console.log(new TextDecoder().decode(rData)); + rData = concatUint8Array([rData, tmp]); } catch (error) { console.error(error); } @@ -110,10 +103,8 @@ export class Firehose { getStatus(resp) { if (resp.hasOwnProperty("value")) { - console.log("In getStatus") let value = resp["value"]; if (value == "ACK" || value == "true" ) { - console.log("IN value = ACK") return true; } else { return false; diff --git a/QDL/sahara.js b/QDL/sahara.js index ec3c1b0..fe3b4a9 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -27,13 +27,10 @@ export class Sahara { if (v.length > 1){ if (v[0] == 0x01){ let pkt = this.ch.pkt_cmd_hdr(v); - console.log("sahara cmd:", pkt.cmd); if (pkt.cmd === cmd_t.SAHARA_HELLO_REQ) { let rsp = this.ch.pkt_hello_req(v); this.pktSize = rsp.cmd_packet_length; this.version = rsp.version; - console.log("pktSize:", this.pktSize); - console.log("version:", this.version); return { "mode" : "sahara", "cmd" : cmd_t.SAHARA_HELLO_REQ, "data" : rsp }; // TODO: probably don't need from here downward till end of this func } else if (v_text.includes("") this.cdc._usbwrite(data); let resp = await this.cdc._usbRead(); @@ -64,19 +60,16 @@ export class Sahara { } else { try { await this.cmdModeSwitch(sahara_mode_t.SAHARA_MODE_COMMAND); - console.log("successfully switch mode in sahara to Command Mode"); } catch (error) { console.error(error); } } let connectResp = await this.connect(); if ((connectResp["mode"] != "sahara")) { - console.log("failed reconnect sahara"); return ""; } console.log("Uploading Programmer..."); let programmer = new Uint8Array(await this.loadProgrammerFromLocal()); - console.log("programmer:", programmer); if (!(await this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version))) { return ""; } @@ -86,11 +79,9 @@ export class Sahara { let loop = 0; while (datalen >= 0 || done){ let resp = await this.getResponse(); - console.log("finish first getresponse"); let cmd if (resp.hasOwnProperty("cmd")){ cmd = resp["cmd"]; - console.log("resp has cmd property:", cmd); } else { console.error("Timeout while uploading loader. Wrong loader?"); return "" @@ -103,11 +94,11 @@ export class Sahara { // TODO: Probably not necessary if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)) { if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) - console.log("64-bit mode detected"); + if (loop == 0) + console.log("64-bit mode detected"); let pkt = resp["data"]; this.id = pkt.image_id; if (this.id >= 0xC){ - console.log("get in this.id >= 0xC"); this.mode = "firehose"; if (loop == 0) console.log("Firehose mode detected, uploading..."); @@ -118,23 +109,15 @@ export class Sahara { loop += 1; let dataOffset = pkt.data_offset; let dataLen = pkt.data_len; - console.log("dataLen:", dataLen); - console.log("compare:", dataOffset + dataLen); - console.log("programmer len:", programmer.length); if (dataOffset + dataLen > programmer.length) { - console.log("in compare dataoffset and programmer len"); const fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); programmer = concatUint8Array([programmer, fillerArray]); } - console.log("ready to slice programmer") let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array - console.log("datatoSend:", dataToSend); await this.cdc?._usbWrite(dataToSend); datalen -= dataLen; } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { - console.log("get into end transfer"); let pkt = resp["data"]; - console.log("pkt.image_txt_status:", pkt.image_tx_status) if (pkt.image_tx_status == status_t.SAHARA_STATUS_SUCCESS){ if (await this.cmdDone()){ console.log("Loader successfully uploaded"); @@ -169,13 +152,11 @@ export class Sahara { async cmdDone(){ const toSendData = packGenerator([cmd_t.SAHARA_DONE_REQ, 0x8]); if (await this.cdc._usbWrite(toSendData)) { - console.log("successfully get in cmdDone after write"); let res = await this.getResponse(); for (let i = 0; i < 500; i += 1) continue; if (res.hasOwnProperty("cmd")){ let cmd = res["cmd"]; - console.log("cmd in getrsp:", cmd); if (cmd == cmd_t.SAHARA_DONE_RSP){ return true } else if (cmd == cmd_t.SAHARA_END_TRANSFER){ @@ -218,11 +199,8 @@ export class Sahara { if (data.length == 0){ return {}; } else if (data_text.includes(" this.epOut?.packetSize){ @@ -134,12 +133,14 @@ export class usbClass { } else { pktSize = cmdPacket.length; } - console.log("default pktSize:", this.epOut?.packetSize); - console.log("pktSize in write:", pktSize); while (offset < cmdPacket.length){ try { - console.log("Transferring Out...") - await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + if (wait){ + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + } else { + this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + await sleep(80); + } offset += pktSize; } catch (error) { console.error(error); @@ -148,4 +149,4 @@ export class usbClass { } return true; } -} +} \ No newline at end of file diff --git a/QDL/utils.js b/QDL/utils.js index 1e3e31e..90f9b98 100644 --- a/QDL/utils.js +++ b/QDL/utils.js @@ -55,3 +55,5 @@ export function compareStringToBytes(compareString, array) { let tArray = new TextDecoder().decode(array); return compareString == tArray; } + +export const sleep = ms => new Promise(r => setTimeout(r, ms)); diff --git a/QDL/xmlParser.js b/QDL/xmlParser.js index 10912d5..0f4d8f1 100644 --- a/QDL/xmlParser.js +++ b/QDL/xmlParser.js @@ -45,6 +45,6 @@ export class xmlParser { }, data); } } - return data; + return content; } } From ee16764e705c62df70b1388e8ed2a930f8daa43a Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 21 Feb 2024 05:09:10 -0500 Subject: [PATCH 011/112] firehose detect partition storage info gpt --- QDL/firehose.js | 224 ++++++++++++++++++++++++++++++++++++++++++++-- QDL/gpt.js | 154 +++++++++++++++++++++++++++++++ QDL/qdl.js | 2 +- QDL/sahara.js | 19 +--- QDL/saharaDefs.js | 60 ++++++------- QDL/usblib.js | 4 +- QDL/utils.js | 28 ++++-- QDL/xmlParser.js | 2 +- 8 files changed, 433 insertions(+), 60 deletions(-) create mode 100644 QDL/gpt.js diff --git a/QDL/firehose.js b/QDL/firehose.js index 4b885cd..26bf581 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -1,5 +1,15 @@ import { xmlParser } from "./xmlParser" -import { concatUint8Array, containsBytes, compareStringToBytes, sleep } from "./utils" +import { concatUint8Array, containsBytes, compareStringToBytes, sleep, loadFileFromLocal } from "./utils" + + +class response { + constructor(resp=false, data=new Uint8Array(), error="", log=[]) { + this.resp = resp; + this.data = data; + this.error = error; + this.log = log; + } +} class cfg { @@ -49,10 +59,88 @@ export class Firehose { `` // TODO: Transfer connectCmd to Uint8Array + //let rsp = await this.xmlSend(connectCmd, false); + //return true; let rsp = await this.xmlSend(connectCmd, false); + if (rsp === null || !rsp.resp) { + if (rsp.error == "") { + return await this.configure(lvl+1); + } + } else { + await this.parseStorage(); + this.luns = this.getLuns(); + return true; + } + } + + + getLuns() { + let luns = []; + for (let i; i < this.cfg.maxlun; i++) + luns.push(i); + return luns; + } + + + async parseStorage() { + const storageInfo = await this.getStorageInfo(); + if (storageInfo === null || storageInfo.resp && storageInfo.data.length === 0) + return false; + const info = storageInfo.data; + if (info.hasOwnProperty("UFS Inquiry Command Output")) { + this.cfg.prod_name = info["UFS Inquiry Command Output"]; + } + if (info.hasOwnProperty("UFS Erase Block Size")) { + this.cfg.block_size = parseInt(info["UFS Erase Block Size"]); + this.cfg.MemoryName = "UFS"; + this.cfg.SECTOR_SIZE_IN_BYTES = 4096; + } + if (info.hasOwnProperty("UFS Total Active LU")) { + this.cfg.maxlun = parseInt(info["UFS Total Active LU"]); + } + if (info.hasOwnProperty("SECTOR_SIZE_IN_BYTES")) { + this.cfg.SECTOR_SIZE_IN_BYTES = parseInt(info["SECTOR_SIZE_IN_BYTES"]); + } + if (info.hasOwnProperty("num_physical_partitions")) { + this.cfg.num_physical = parseInt(info["num_physical_partitions"]) + } return true; } + + async getStorageInfo() { + const data = ""; + let val = await this.xmlSend(data); + if (containsBytes("", val.data) && val.log.length == 0 && val.resp) + return null; + if (val.resp) { + if (val.log !== null) { + let res = {}; + let v; + for (const value of val.log) { + v = value.split("="); + if (v.length > 1) { + res[v[0]] = v[1]; + } else { + if (!value.includes("\"storage_info\"")) { + v = value.split(":"); + if (v.length > 1) + res[v[0]] = v[1].trimStart(); + } + } + } + return { resp: val.resp, data : res}; + } + return { resp : val.resp, data : val.data}; + } else { + if (!val.error !== null && !val.error !== "") { + console.error("failed to open SDCC device"); + } + return null; + } + } + + async xmlSend(data, wait=true) { let dataToSend = new TextEncoder().encode(data).slice(0, this.cfg.MaxXMLSizeInBytes); await this.cdc?._usbWrite(dataToSend, null, wait); @@ -78,17 +166,18 @@ export class Firehose { const status = this.getStatus(resp); if (status !== null) { if (containsBytes("log value=", rData)) { - //let log = this.xml.getLog(rData); - return { "resp" : status, "data" : rData, "log" : "" }; // TODO: getLog() + let log = this.xml.getLog(rData); + return { resp : status, data : rData, log : log, error : "" }; // TODO: getLog() } - return { "resp" : status, "data" : rData }; + return { resp : status, data : rData, log : [] , error : ""}; } } catch (error) { console.error(error); } - return {"resp" : true, "data" : rData}; + return {resp : true, data : rData, log : [], error : ""}; } + async cmdReset() { let data = ""; let val = await this.xmlSend(data); @@ -101,6 +190,131 @@ export class Firehose { } } + + async detectPartition(partitionName) { + let fPartitions = {}; + for (const lun of this.luns) { + const lunName = "Lun" + lun.toString(); + fPartitions[lunName] = [] + const gptNumPartEntries = 0; + const gptPartEntrySize = 0; + const gptPartEntryStartLba = 0; + let [ data, guidGpt ] = await this.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + if (guidGpt === null) { + break; + } else { + if (guidGpt.partentries.hasOwnProperty(partitionName)) { + return [true, lun, guidGpt.partentries[partitionName]] + } + } + for (const part in guidGpt.partentries) + fPartitions[lunName] = part; + } + return [false, fPartitions] + } + + + async getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba) { + try { + let resp = await this.cmdReadBuffer(lun, 0, 2); + } catch (error) { + console.log(error); + } + if (!resp.resp) { + console.error(resp.error); + return [null, null]; + } + let data = resp.data; + const guidGpt = gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + try { + let header = guidGpt.parseHeader(data, this.cfg.SECTOR_SIZE_IN_BYTES); + if (containsBytes("EFI PART", header.signature)) { + const gptSize = (header.partEntryStartLba * this.cfg.SECTOR_SIZE_IN_BYTES) + + (header.numPartEntry * header.partEntrySize); + let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES) + if (gptSize % this.cfg.SECTOR_SIZE_IN_BYTES != 0) + sectors += 1; + if (sectors === 0) + sectors = 64; + if (sectors > 64) + sectors = 64; + data = await this.cmdReadBuffer(lun, 0, sectors); + if (containsBytes("", data)) + return [null, null]; + guidGpt.parse(data.data, this.cfg.SECTOR_SIZE_IN_BYTES); + return [data.data, guidGpt]; + } else { + return [null, null]; + } + } catch (error) { + console.error(error); + return [null, null] + } + } + + + async cmdReadBuffer(physicalPartitionNumber, startSector, numPartitionSectors) { + let prog = 0; + const data = `\n` + let rsp = await this.xmlSend(data); + let resData = new Uint8Array(); + if (!rsp.resp){ + return rsp + } else { + let bytesToRead = this.cfg.SECTOR_SIZE_IN_BYTES * numPartitionSectors; + let total = bytesToRead; + while (bytesToRead > 0) { + let tmp = await this.cdc._usbRead(Math.min(this.cdc.maxSize, bytesToRead)); + const size = tmp.length; + bytesToRead -= size; + resData = concatUint8Array([resData, tmp]); + } + const wd = await this.waitForData(); + const info = this.xml.getLog(wd); + rsp = this.xml.getReponse(wd); + if (rsp.hasOwnProperty("value")) { + if (rsp["value"] !== "ACK") { + return new response( { resp : false, data : resData, error : info}); + } else if (rsp.hasOwnProperty("rawmode")) { + if (rsp["rawmode"] === "false") + return new response({ resp : true, data : resData}); + } + } else { + console.error("Failed read buffer"); + return new response({ resp: false, data : resData, error : rsp[2]}); + } + } + let resp = rsp["value"] === "ACK"; + return response({ resp : resp, data : resData, error : rsp[2]}); + } + + + async waitForData() { + let tmp = new Uint8Array(); + let timeout = 0; + while (!containsBytes("response value", tmp)) { + let res = await this.cdc._usbRead(); + if (compareStringToBytes("", res)) { + timeout += 1; + if (timeout === 4) + break; + await sleep(20); + } + tmp = concatUint8Array([tmp, res]); + return tmp; + } + } + + + // display? + async cmdProgram(physicalPartitionNumber, startSector, fileName) { + let fname = new Uint8Array(await loadFileFromLocal()) + } + + getStatus(resp) { if (resp.hasOwnProperty("value")) { let value = resp["value"]; diff --git a/QDL/gpt.js b/QDL/gpt.js new file mode 100644 index 0000000..8887ead --- /dev/null +++ b/QDL/gpt.js @@ -0,0 +1,154 @@ +const { containsBytes } = require("./utils"); + +class structHelper { + pos = 0; + + constructor(data, pos = 0) { + this.pos = pos; + this.data = data; + } + + qword(littleEndian=true) { + const view = new Dataview(this.data.slice(this.pos, this.pos+8), 0); + this.pos += 8; + return view.getBigUint64(0, littleEndian); + } + + dword(littleEndian=true) { + let view = new DataView(this.data.slice(this.pos, this.pos+4).buffer, 0); + this.pos += 4; + return view.getUint32(0, littleEndian); + } + + bytes(rlen=1) { + const dat = this.data.slice(this.pos, this.pos+rlen); + this.pos += rlen; + if (rlen == 1) + return dat[0]; + return dat; + } + + toString(rlen=1) { + const dat = this.data.slice(this.pos, this.pos+rlen); + this.pos += rlen; + return dat; + } +} + + +class gptHeader { + constructor(data) { + this.sh = new structHelper(data); + this.signature = sh.bytes(8); + this.revision = sh.dword(); + this.header_size = sh.dword(); + this.crc32 = sh.dword(); + this.reserved = sh.dword(); + this.current_lba = sh.qword(); + this.backup_lba = sh.qword(); + this.first_usable_lba = sh.qword(); + this.last_usable_lba = sh.qword(); + this.disk_guid = sh.bytes(16); + this.part_entry_start_lba = sh.qword(); + this.num_part_entries = sh.dword(); + this.part_entry_size = sh.dword(); + this.crc32_part_entries = sh.dword(); + } +} + +class gptPartition { + constructor(data) { + sh = new structHelper(data) + this.type = sh.bytes(16); + this.unique = sh.bytes(16); + this.first_lba = sh.qword(); + this.last_lba = sh.qword(); + this.flags = sh.qword(); + this.name = sh.string(72); + } +} + + +class partf { + unique = new Uint8Array(); + firstLba = 0; + lastLba = 0; + flags = 0; + sector = 0; + sectors = 0; + type = new Uint8Array(); + name = ""; + entryOffset = 0; +} + + +// efi_type of leeco : 747038530 +class gpt { + constructor(numPartEntries=0, partEntrySize=0, partEntryStartLba=0) { + this.numPartEntries = numPartEntries; + this.partEntrySize = partEntrySize; + this.partEntryStartLba = partEntryStartLba; + this.totalSectors = null; + this.header = null; + this.sectorSize = null; + this.partentries = []; + } + + parseheader(gptData, sectorSize=512){ + return new gptHeader(gptData.slice(sectorSize, sectorSize + 0x5C)); + } + + parse(gptData, sectorSize=512) { + this.header = new gptHeader(gptData.slice(sectorsize, sectorsize + 0x5C)); + this.sectorSize = sectorSize; + if (!containsBytes("EFI PART", this.header.signature)) + return false; + if (this.header.revision != 0x10000) { + console.error("Unknown GPT revision."); + return false; + } + let start; + if (this.partEntryStartLba != 0) { + start = self.partEntryStartLba; + } else { + start = this.header.partEntryStartLba * sectorSize; + } + + let entrySize = this.header.partEntrySize; + this.partentries = {}; + + + let numPartEntries = this.header.numPartEntries; + + // TODO: + //for (let idx=0; idx < num_part_entries; idx++) { + // let data = gptData.slice(start + (idx * entrysize), start + (idx * entrysize) + entrysize) + // if (new DataView(data.slice(16,32),0).getUint16(0) == 0) + // break + // let partentry = new gptPartition(data) + // let pa = new partf() + // guid1 = unpack(" { - let reader = new FileReader(); - reader.onload = () => { - resolve(reader.result); - }; - reader.onerror = () => { - reject(reader.error); - }; - reader.readAsArrayBuffer(blob); - }); - } async cmdDone(){ const toSendData = packGenerator([cmd_t.SAHARA_DONE_REQ, 0x8]); diff --git a/QDL/saharaDefs.js b/QDL/saharaDefs.js index d22255d..4da29e0 100644 --- a/QDL/saharaDefs.js +++ b/QDL/saharaDefs.js @@ -81,7 +81,7 @@ export class CommandHandler { process.exit(1) } let st = new structHelper_io(data); - return { cmd : st.dword(0), len : st.dword(4) } + return { cmd : st.dword(), len : st.dword() } } pkt_hello_req(data) { @@ -91,18 +91,18 @@ export class CommandHandler { } let st = new structHelper_io(data); return { - cmd : st.dword(0), - len : st.dword(4), - version : st.dword(8), - version_supported : st.dword(12), - cmd_packet_length : st.dword(16), - mode : st.dword(20), - reserved1 : st.dword(24), - reserved2 : st.dword(28), - reserved3 : st.dword(32), - reserved4 : st.dword(36), - reserved5 : st.dword(40), - reserved6 : st.dword(44), + cmd : st.dword(), + len : st.dword(), + version : st.dword(), + version_supported : st.dword(), + cmd_packet_length : st.dword(), + mode : st.dword(), + reserved1 : st.dword(), + reserved2 : st.dword(), + reserved3 : st.dword(), + reserved4 : st.dword(), + reserved5 : st.dword(), + reserved6 : st.dword(), } } pkt_image_end(data) { @@ -112,10 +112,10 @@ export class CommandHandler { } let st = new structHelper_io(data); return { - cmd : st.dword(0), - len : st.dword(4), - image_id : st.dword(8), - image_tx_status : st.dword(12), + cmd : st.dword(), + len : st.dword(), + image_id : st.dword(), + image_tx_status : st.dword(), } } @@ -126,9 +126,9 @@ export class CommandHandler { } let st = new structHelper_io(data); return { - cmd : st.dword(0), - len : st.dword(4), - image_tx_status : st.dword(8) + cmd : st.dword(), + len : st.dword(), + image_tx_status : st.dword() } } @@ -139,11 +139,11 @@ export class CommandHandler { } let st = new structHelper_io(data) return { - cmd : st.dword(0), - len : st.dword(4), - image_id : Number(st.qword(8)), - data_offset : Number(st.qword(16)), - data_len : Number(st.qword(24)), + cmd : st.dword(), + len : st.dword(), + image_id : Number(st.qword()), + data_offset : Number(st.qword()), + data_len : Number(st.qword()), } } @@ -154,10 +154,10 @@ export class CommandHandler { } let st = new structHelper_io(data) return { - cmd : st.dword(0), - len : st.dword(4), - client_cmd : st.dword(8), - data_len : st.dword(12), + cmd : st.dword(), + len : st.dword(), + client_cmd : st.dword(), + data_len : st.dword(), } } -} \ No newline at end of file +} diff --git a/QDL/usblib.js b/QDL/usblib.js index d52a097..aecbf64 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -24,6 +24,8 @@ export class usbClass { this.epIn = null; this.epOut = null; this._registeredUsbListeners = null; + // TODO: auto maxSize + this.maxSize = 512; } get connected() { @@ -149,4 +151,4 @@ export class usbClass { } return true; } -} \ No newline at end of file +} diff --git a/QDL/utils.js b/QDL/utils.js index 90f9b98..a8dd517 100644 --- a/QDL/utils.js +++ b/QDL/utils.js @@ -2,17 +2,20 @@ export class structHelper_io { data; direction; - constructor(data) { + constructor(data, pos=0) { + this.pos = pos this.data = data; } - dword(idx_start, littleEndian=true) { - let view = new DataView(this.data.slice(idx_start, idx_start+4).buffer, 0); + dword(littleEndian=true) { + let view = new DataView(this.data.slice(this.pos, this.pos+4).buffer, 0); + this.pos += 4; return view.getUint32(0, littleEndian); } - qword(idx_start, littleEndian=true) { - let view = new DataView(this.data.slice(idx_start, idx_start+8).buffer, 0); + qword(littleEndian=true) { + let view = new DataView(this.data.slice(this.pos, this.pos+8).buffer, 0); + this.pos += 8; return view.getBigUint64(0, littleEndian); } } @@ -56,4 +59,19 @@ export function compareStringToBytes(compareString, array) { return compareString == tArray; } +export async function loadFileFromLocal() { + const [fileHandle] = await window.showOpenFilePicker(); + const blob = await fileHandle.getFile(); + return new Promise((resolve, reject) => { + let reader = new FileReader(); + reader.onload = () => { + resolve(reader.result); + }; + reader.onerror = () => { + reject(reader.error); + }; + reader.readAsArrayBuffer(blob); + }); +} + export const sleep = ms => new Promise(r => setTimeout(r, ms)); diff --git a/QDL/xmlParser.js b/QDL/xmlParser.js index 0f4d8f1..10912d5 100644 --- a/QDL/xmlParser.js +++ b/QDL/xmlParser.js @@ -45,6 +45,6 @@ export class xmlParser { }, data); } } - return content; + return data; } } From db7c27382b06ceaa0d868aac3265ae7b12fc8f23 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 22 Feb 2024 02:28:26 -0500 Subject: [PATCH 012/112] can detect partition --- QDL/firehose.js | 61 +++++++++++++++++++++++++++++-------------------- QDL/gpt.js | 56 +++++++++++++++++++++++---------------------- QDL/qdl.js | 2 ++ 3 files changed, 67 insertions(+), 52 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index 26bf581..d42ac63 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -1,5 +1,6 @@ import { xmlParser } from "./xmlParser" import { concatUint8Array, containsBytes, compareStringToBytes, sleep, loadFileFromLocal } from "./utils" +import { gpt } from "./gpt" class response { @@ -12,7 +13,6 @@ class response { } class cfg { - constructor() { this.TargetName = ""; this.Version = ""; @@ -35,13 +35,14 @@ class cfg { export class Firehose { cdc; - //xml; + xml; cfg constructor(cdc) { this.cdc = cdc; this.xml = new xmlParser(); this.cfg = new cfg(); + this.luns = []; } async configure(lvl) { @@ -76,7 +77,7 @@ export class Firehose { getLuns() { let luns = []; - for (let i; i < this.cfg.maxlun; i++) + for (let i=0; i < this.cfg.maxlun; i++) luns.push(i); return luns; } @@ -111,7 +112,7 @@ export class Firehose { async getStorageInfo() { const data = ""; let val = await this.xmlSend(data); - if (containsBytes("", val.data) && val.log.length == 0 && val.resp) + if (compareStringToBytes("", val.data) && val.log.length == 0 && val.resp) return null; if (val.resp) { if (val.log !== null) { @@ -164,17 +165,25 @@ export class Firehose { try { const resp = this.xml.getReponse(rData); // input is Uint8Array const status = this.getStatus(resp); - if (status !== null) { - if (containsBytes("log value=", rData)) { + if (resp.hasOwnProperty("rawmode")) { + if (resp["rawmode"] == "false") { let log = this.xml.getLog(rData); - return { resp : status, data : rData, log : log, error : "" }; // TODO: getLog() + return new response(status, rData, "", log) + } + } else { + if (status) { + if (containsBytes("log value=", rData)) { + let log = this.xml.getLog(rData); + //return { resp : status, data : rData, log : log, error : "" }; // TODO: getLog() + return new response(status, rData, "", log); + } + return new response(status, rData); } - return { resp : status, data : rData, log : [] , error : ""}; } } catch (error) { console.error(error); } - return {resp : true, data : rData, log : [], error : ""}; + return new response(true, rData); } @@ -215,23 +224,24 @@ export class Firehose { async getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba) { + let resp; try { - let resp = await this.cmdReadBuffer(lun, 0, 2); + resp = await this.cmdReadBuffer(lun, 0, 2); } catch (error) { - console.log(error); + console.error(error); } if (!resp.resp) { console.error(resp.error); return [null, null]; } let data = resp.data; - const guidGpt = gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + let guidGpt = new gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); try { - let header = guidGpt.parseHeader(data, this.cfg.SECTOR_SIZE_IN_BYTES); + const header = guidGpt.parseHeader(data, this.cfg.SECTOR_SIZE_IN_BYTES); if (containsBytes("EFI PART", header.signature)) { - const gptSize = (header.partEntryStartLba * this.cfg.SECTOR_SIZE_IN_BYTES) + - (header.numPartEntry * header.partEntrySize); - let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES) + const gptSize = (header.part_entry_start_lba * this.cfg.SECTOR_SIZE_IN_BYTES) + + (header.num_part_entries * header.part_entry_size); + let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES); if (gptSize % this.cfg.SECTOR_SIZE_IN_BYTES != 0) sectors += 1; if (sectors === 0) @@ -239,7 +249,7 @@ export class Firehose { if (sectors > 64) sectors = 64; data = await this.cmdReadBuffer(lun, 0, sectors); - if (containsBytes("", data)) + if (compareStringToBytes("", data.data)) return [null, null]; guidGpt.parse(data.data, this.cfg.SECTOR_SIZE_IN_BYTES); return [data.data, guidGpt]; @@ -254,7 +264,7 @@ export class Firehose { async cmdReadBuffer(physicalPartitionNumber, startSector, numPartitionSectors) { - let prog = 0; + //let prog = 0; const data = ` 0) { let tmp = await this.cdc._usbRead(Math.min(this.cdc.maxSize, bytesToRead)); const size = tmp.length; @@ -277,18 +287,18 @@ export class Firehose { rsp = this.xml.getReponse(wd); if (rsp.hasOwnProperty("value")) { if (rsp["value"] !== "ACK") { - return new response( { resp : false, data : resData, error : info}); + return new response(false, resData, info); } else if (rsp.hasOwnProperty("rawmode")) { if (rsp["rawmode"] === "false") - return new response({ resp : true, data : resData}); + return new response(true, resData); } } else { console.error("Failed read buffer"); - return new response({ resp: false, data : resData, error : rsp[2]}); + return new response(false, resData, rsp[2]); } } let resp = rsp["value"] === "ACK"; - return response({ resp : resp, data : resData, error : rsp[2]}); + return response(resp, resData, rsp[2]); } @@ -299,13 +309,14 @@ export class Firehose { let res = await this.cdc._usbRead(); if (compareStringToBytes("", res)) { timeout += 1; - if (timeout === 4) + if (timeout === 4){ break; + } await sleep(20); } tmp = concatUint8Array([tmp, res]); - return tmp; } + return tmp; } diff --git a/QDL/gpt.js b/QDL/gpt.js index 8887ead..1a3a7ed 100644 --- a/QDL/gpt.js +++ b/QDL/gpt.js @@ -9,9 +9,9 @@ class structHelper { } qword(littleEndian=true) { - const view = new Dataview(this.data.slice(this.pos, this.pos+8), 0); + const view = new DataView(this.data.slice(this.pos, this.pos+8).buffer, 0); this.pos += 8; - return view.getBigUint64(0, littleEndian); + return Number(view.getBigUint64(0, littleEndian)); } dword(littleEndian=true) { @@ -38,7 +38,7 @@ class structHelper { class gptHeader { constructor(data) { - this.sh = new structHelper(data); + let sh = new structHelper(data); this.signature = sh.bytes(8); this.revision = sh.dword(); this.header_size = sh.dword(); @@ -56,15 +56,16 @@ class gptHeader { } } + class gptPartition { constructor(data) { - sh = new structHelper(data) + let sh = new structHelper(data) this.type = sh.bytes(16); this.unique = sh.bytes(16); this.first_lba = sh.qword(); this.last_lba = sh.qword(); this.flags = sh.qword(); - this.name = sh.string(72); + this.name = sh.toString(72); } } @@ -82,8 +83,7 @@ class partf { } -// efi_type of leeco : 747038530 -class gpt { +export class gpt { constructor(numPartEntries=0, partEntrySize=0, partEntryStartLba=0) { this.numPartEntries = numPartEntries; this.partEntrySize = partEntrySize; @@ -91,15 +91,15 @@ class gpt { this.totalSectors = null; this.header = null; this.sectorSize = null; - this.partentries = []; + this.partentries = {}; } - parseheader(gptData, sectorSize=512){ + parseHeader(gptData, sectorSize=512){ return new gptHeader(gptData.slice(sectorSize, sectorSize + 0x5C)); } parse(gptData, sectorSize=512) { - this.header = new gptHeader(gptData.slice(sectorsize, sectorsize + 0x5C)); + this.header = new gptHeader(gptData.slice(sectorSize, sectorSize + 0x5C)); this.sectorSize = sectorSize; if (!containsBytes("EFI PART", this.header.signature)) return false; @@ -111,44 +111,46 @@ class gpt { if (this.partEntryStartLba != 0) { start = self.partEntryStartLba; } else { - start = this.header.partEntryStartLba * sectorSize; + start = this.header.part_entry_start_lba * sectorSize; } - let entrySize = this.header.partEntrySize; + let entrySize = this.header.part_entry_size; this.partentries = {}; - - let numPartEntries = this.header.numPartEntries; + let numPartEntries = this.header.num_part_entries; // TODO: - //for (let idx=0; idx < num_part_entries; idx++) { - // let data = gptData.slice(start + (idx * entrysize), start + (idx * entrysize) + entrysize) - // if (new DataView(data.slice(16,32),0).getUint16(0) == 0) - // break - // let partentry = new gptPartition(data) - // let pa = new partf() + for (let idx=0; idx < numPartEntries; idx++) { + const data = gptData.slice(start + (idx * entrySize), start + (idx * entrySize) + entrySize); + if (new DataView(data.slice(16,32).buffer, 0).getUint16(0, true) == 0) + break; + let partentry = new gptPartition(data); + let pa = new partf(); // guid1 = unpack(" index % 2 === 0 && element === 0); + let nameWithoutNull = partentry.name.slice(0, nullIndex); + let decodedName = new TextDecoder('utf-16').decode(nameWithoutNull); + pa.name = decodedName; // if pa.type == "EFI_UNUSED": // continue - // self.partentries[pa.name]=pa - //} - //self.totalsectors = self.header.first_usable_lba + self.header.last_usable_lba - return True + this.partentries[pa.name] = pa; + } + this.totalsectors = this.header.first_usable_lba + this.header.last_usable_lba; + return true; } } diff --git a/QDL/qdl.js b/QDL/qdl.js index e3aa57d..af2f29c 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -44,6 +44,8 @@ export class qdlDevice { console.log("mode from uploadloader:", mode); } await this.firehose?.configure(0); + let dp = await this.firehose?.detectPartition("boot"); + console.log("Partition information:", dp); await this.firehose?.cmdReset(); } catch (error) { console.error(error); From 9b6da711abdced5f4b2022ebc8bc7362f06376e5 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 22 Feb 2024 04:05:12 -0500 Subject: [PATCH 013/112] can write --- QDL/firehose.js | 47 ++++++++++++++++++++++++++++++++++++++++++++++- QDL/qdl.js | 29 +++++++++++++++++++++++++++-- QDL/usblib.js | 6 +++++- 3 files changed, 78 insertions(+), 4 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index d42ac63..50e792b 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -321,8 +321,53 @@ export class Firehose { // display? + // filename not used until I use the navigator.storage, currently choose image file manually async cmdProgram(physicalPartitionNumber, startSector, fileName) { - let fname = new Uint8Array(await loadFileFromLocal()) + let flashImg = new Uint8Array(await loadFileFromLocal()) + const total = flashImg.length; + let bytesToWrite = total; + let numPartitionSectors = Math.floor(total/this.cfg.SECTOR_SIZE_IN_BYTES); + if (total % this.cfg.SECTOR_SIZE_IN_BYTES !== 0) + numPartitionSectors += 1; + const data = `\n` + + `\n`; + let rsp = await this.xmlSend(data); + let offSet = 0; + if (rsp.resp) { + while (bytesToWrite > 0) { + const wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); + console.log + let wdata = flashImg.slice(offSet, offSet + wlen); + offSet += wlen; + bytesToWrite -= wlen; + + if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ + let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + + this.cfg.SECTOR_SIZE_IN_BYTES; + const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); + wdata = concatUint8Array([wdata, fillArray]); + } + await this.cdc._usbWrite(wdata); + console.log(`Progress: ${Math.floor(offSet/total)*100}%`); + await this.cdc._usbWrite(new Uint8Array(0), null, true, true); + } + const wd = await this.waitForData(); + const log = this.xml.getLog(wd); + const rsp = this.xml.getReponse(wd); + if (rsp.hasOwnProperty("value")) { + if (rsp["value"] !== "ACK") { + console.error("ERROR") + return false; + } + } else { + console.error("Error:", rsp); + return false; + } + } + return true; } diff --git a/QDL/qdl.js b/QDL/qdl.js index af2f29c..22aa352 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -1,6 +1,7 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" +import { loadFileFromLocal } from "./utils"; export class qdlDevice { cdc; @@ -44,8 +45,32 @@ export class qdlDevice { console.log("mode from uploadloader:", mode); } await this.firehose?.configure(0); - let dp = await this.firehose?.detectPartition("boot"); - console.log("Partition information:", dp); + + let startSector = 0; + let partitionName = "boot"; + let dp = await this.firehose?.detectPartition(partitionName); + if (dp[0]) { + let lun = dp[1]; + const imgSize = new Uint8Array(await loadFileFromLocal()).length; + let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); + if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) + imgSectors += 1; + if (partitionName.toLowerCase() !== "gpt") { + const partition = dp[2]; + if (imgSectors > partition.sectors) { + console.error("partition has fewer sectors compared to the flashing image"); + return false; + } + startSector = partition.sector; + //console.log(`startSector of ${partitionName} is ${startSector}`); + if (await this.firehose.cmdProgram(lun, startSector, "")) { + console.log(`Wrote to startSector: ${startSector}`); + } else { + console.error("Error writing image"); + } + } + } + await this.firehose?.cmdReset(); } catch (error) { console.error(error); diff --git a/QDL/usblib.js b/QDL/usblib.js index aecbf64..95918e8 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -127,7 +127,7 @@ export class usbClass { return respData; } - async _usbWrite(cmdPacket, pktSize=null, wait=true) { + async _usbWrite(cmdPacket, pktSize=null, wait=true, force=false) { let offset = 0; if (pktSize === null) if (cmdPacket.length > this.epOut?.packetSize){ @@ -135,6 +135,10 @@ export class usbClass { } else { pktSize = cmdPacket.length; } + + if (cmdPacket.length === 0 && force) + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); + while (offset < cmdPacket.length){ try { if (wait){ From 792656097fea54d63809d2d005bf1fa318871586 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 24 Feb 2024 22:42:45 -0500 Subject: [PATCH 014/112] can erase --- QDL/firehose.js | 42 +++++++++++++++++++++++++-- QDL/qdl.js | 73 ++++++++++++++++++++++++++++++----------------- QDL/sahara.js | 2 +- QDL/saharaDefs.js | 2 +- QDL/usblib.js | 10 +++++-- 5 files changed, 97 insertions(+), 32 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index 50e792b..95cb98c 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -334,15 +334,15 @@ export class Firehose { ` num_partition_sectors=\"${numPartitionSectors}\"` + ` physical_partition_number=\"${physicalPartitionNumber}\"` + ` start_sector=\"${startSector}\" />\n`; + let rsp = await this.xmlSend(data); let offSet = 0; if (rsp.resp) { - while (bytesToWrite > 0) { + while (offSet < total) { const wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); console.log let wdata = flashImg.slice(offSet, offSet + wlen); offSet += wlen; - bytesToWrite -= wlen; if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + @@ -371,6 +371,44 @@ export class Firehose { } + async cmdErase(physicalPartitionNumber, startSector, numPartitionSectors) { + const data = `\n` + + `\n`; + + let rsp = await this.xmlSend(data) + let empty = new Uint8Array(this.cfg.MaxPayloadSizeToTargetInBytes).fill(0x00); + let pos = 0, bytesToWrite = this.cfg.SECTOR_SIZE_IN_BYTES * numPartitionSectors; + const total = bytesToWrite; + if (rsp.resp) { + while (bytesToWrite > 0) { + let wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeToTargetInBytes); + await this.cdc._usbWrite(empty.slice(0, wlen)); + bytesToWrite -= wlen; + pos += wlen; + await this.cdc._usbWrite(new Uint8Array(0), null, true, true); + console.log(`Finished: ${Math.floor(pos/total)*100}%`); + } + const res = await this.waitForData(); + //const info = this.xml.getLog(res); + const response = this.xml.getReponse(res); + if (response.hasOwnProperty("value")) { + if (response["value"] !== "ACK") { + console.error("ERROR") + return false; + } + } else { + console.error("Error:", rsp); + return false; + } + } + console.log("Finish erasing"); + return true; + } + + getStatus(resp) { if (resp.hasOwnProperty("value")) { let value = resp["value"]; diff --git a/QDL/qdl.js b/QDL/qdl.js index 22aa352..5b80e7b 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -36,6 +36,52 @@ export class qdlDevice { /** TODO: check for connected to sahara * or mode = firehose then don't need to connect */ + + async flasbBlob(partitionName) { + let startSector = 0; + let dp = await this.firehose?.detectPartition(partitionName); + if (dp[0]) { + let lun = dp[1]; + const imgSize = new Uint8Array(await loadFileFromLocal()).length; + let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); + if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) + imgSectors += 1; + if (partitionName.toLowerCase() !== "gpt") { + const partition = dp[2]; + if (imgSectors > partition.sectors) { + console.error("partition has fewer sectors compared to the flashing image"); + return false; + } + startSector = partition.sector; + //console.log(`startSector of ${partitionName} is ${startSector}`); + if (await this.firehose.cmdProgram(lun, startSector, "")) { + console.log(`Wrote to startSector: ${startSector}`); + } else { + console.error("Error writing image"); + } + } + } + } + + async erase(partitionName) { + let luns = this.firehose.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + if (guidGpt === null) + break; + if (guidGpt.partentries.hasOwnProperty(partitionName)) { + const partition = guidGpt.partentries[partitionName]; + console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors: ${partition.sectors}`); + await this.firehose.cmdErase(lun, partition.sector, partition.sectors); + console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sector count ${partition.sectors}`) + } else { + console.log(`Couldn't erase partition ${partitionName}. Either wrong type or not in lun ${lun}`); + continue; + } + } + } + async reset() { try { let resp = await this.doconnect(); @@ -45,32 +91,7 @@ export class qdlDevice { console.log("mode from uploadloader:", mode); } await this.firehose?.configure(0); - - let startSector = 0; - let partitionName = "boot"; - let dp = await this.firehose?.detectPartition(partitionName); - if (dp[0]) { - let lun = dp[1]; - const imgSize = new Uint8Array(await loadFileFromLocal()).length; - let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); - if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) - imgSectors += 1; - if (partitionName.toLowerCase() !== "gpt") { - const partition = dp[2]; - if (imgSectors > partition.sectors) { - console.error("partition has fewer sectors compared to the flashing image"); - return false; - } - startSector = partition.sector; - //console.log(`startSector of ${partitionName} is ${startSector}`); - if (await this.firehose.cmdProgram(lun, startSector, "")) { - console.log(`Wrote to startSector: ${startSector}`); - } else { - console.error("Error writing image"); - } - } - } - + await this.erase("cache"); await this.firehose?.cmdReset(); } catch (error) { console.error(error); diff --git a/QDL/sahara.js b/QDL/sahara.js index bd11b18..42c48a1 100644 --- a/QDL/sahara.js +++ b/QDL/sahara.js @@ -234,4 +234,4 @@ export class Sahara { return false; } } -} +} \ No newline at end of file diff --git a/QDL/saharaDefs.js b/QDL/saharaDefs.js index 4da29e0..6b0a2c3 100644 --- a/QDL/saharaDefs.js +++ b/QDL/saharaDefs.js @@ -160,4 +160,4 @@ export class CommandHandler { data_len : st.dword(), } } -} +} \ No newline at end of file diff --git a/QDL/usblib.js b/QDL/usblib.js index 95918e8..b44e2b7 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -68,7 +68,13 @@ export class usbClass { try { await this.device?.open(); await this.device?.selectConfiguration(1); - await this.device?.claimInterface(0); + try { + await this.device?.releaseInterface(0); + } catch (error) { + console.log(error); + console.log("can't release interface"); + } + await this.device?.claimInterface(this.device.configuration.interfaces[0].interfaceNumber); } catch (error) { throw error; } @@ -145,7 +151,7 @@ export class usbClass { await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); } else { this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); - await sleep(80); + await sleep(80); } offset += pktSize; } catch (error) { From 074a66d473232a49040b82013231159784a0e62b Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 24 Feb 2024 23:35:50 -0500 Subject: [PATCH 015/112] can get active slot - haven't tested --- QDL/qdl.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/QDL/qdl.js b/QDL/qdl.js index 5b80e7b..fbfedd1 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -82,6 +82,27 @@ export class qdlDevice { } } + async getActiveSlot() { + const luns = this.firehose?.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + //for (const lun of luns) { + const lun = luns[0]; + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + if (guidGpt === null) + return "" + for (const partitionName in guidGpt.partentries) { + const slot = partitionName.slice(-2); + if (slot == "_a") { + return "a"; + } else if (slot == "b") { + return "b"; + } else { + console.error("Can't detect slot A or B"); + return "" + } + } + //} + } async reset() { try { let resp = await this.doconnect(); From ad5b51937ead8d1aa622d9500e91164cc2d0e53a Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 25 Feb 2024 04:36:54 -0500 Subject: [PATCH 016/112] setactive slot --- QDL/firehose.js | 73 ++++++++++++++++-- QDL/gpt.js | 199 +++++++++++++++++++++++++++++++++++++++++++----- QDL/qdl.js | 22 +++++- package.json | 1 + pnpm-lock.yaml | 8 ++ 5 files changed, 274 insertions(+), 29 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index 95cb98c..b764326 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -336,13 +336,14 @@ export class Firehose { ` start_sector=\"${startSector}\" />\n`; let rsp = await this.xmlSend(data); - let offSet = 0; + let offset = 0; if (rsp.resp) { - while (offSet < total) { + while (bytesToWrite > 0) { const wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); console.log - let wdata = flashImg.slice(offSet, offSet + wlen); - offSet += wlen; + let wdata = flashImg.slice(offset, offset + wlen); + offset += wlen; + bytesToWrite -= wlen; if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + @@ -351,7 +352,7 @@ export class Firehose { wdata = concatUint8Array([wdata, fillArray]); } await this.cdc._usbWrite(wdata); - console.log(`Progress: ${Math.floor(offSet/total)*100}%`); + console.log(`Progress: ${Math.floor(offset/total)*100}%`); await this.cdc._usbWrite(new Uint8Array(0), null, true, true); } const wd = await this.waitForData(); @@ -371,6 +372,68 @@ export class Firehose { } + async cmdSetActiveSlot(slot) { + slot = slot.toLowerCase(); + const luns = this.getLuns(); + let partSlots = {}; + if (slot == "a") { + partSlots["_a"] = true; + partSlots["_b"] = false; + } else if (slot == "b") { + partSlots["_a"] = false; + partSlots["_b"] = true; + } else { + console.error("Only slots a or b are accepted. Aborting."); + return false; + } + for (const lun of luns) { + const [ data, guidGpt ] = await this.getGpt(lun, 0, 0, 0); + if (guidGpt === null) + break; + for (const partitionName in guidGpt.partentries) { + const gp = new gpt(); + slot = partitionName.toLowerCase().slice(-2); + if (slot === "a" || slot === "b") { + const [ pdata, pOffset ] = gp.patch(data, partitionName, partSlots[slot]); + data.splice(pOffset, pdata.length, pdata); + let wdata = gp.fixGptCrc(data); + if (wdata !== null) { + const startSectorPath = Math.floor(pOffset/this.cfg.SECTOR_SIZE_IN_BYTES); + const byteOffsetPatch = pOffset % this.cfg.SECTOR_SIZE_IN_BYTES; + const headerOffset = gp.header.current_lba * gp.sectorSize; + const startSectorHdr = Math.floor(headerOffset/this.cfg.SECTOR_SIZE_IN_BYTES); + const header = wdata.slice(startSectorHdr, startSectorHdr+gp.header.header_size); + await this.cmdPatch(lun, startSectorPath, byteOffsetPatch, pdata, pdata.length); + await this.cmdPatch(lun, headerOffset, 0, header, pdata.length); + } + } + } + } + } + + + async cmdPatch(physical_partition_number, start_sector, byte_offset, value, size_in_bytes) { + const data = `\n` + + `\n`; + + let rsp = await this.xmlSend(data); + if (rsp.resp) { + console.log("Patch:\n--------------------\n"); + console.log(rsp.data); + return true; + } else { + console.error(`Error: ${rsp.error}`); + return false; + } + } + + async cmdErase(physicalPartitionNumber, startSector, numPartitionSectors) { const data = `\n` + ` byte.toString(16).padStart(2, '0')) + .join(''); + + pa.unique = `${guid1.toString(16).padStart(8, '0')}-${guid2.toString(16).padStart(4, '0')}-${guid3.toString(16).padStart(4, '0')}-${guid4.toString(16).padStart(4, '0')}-${guid5}`; + pa.sector = partentry.first_lba; + pa.sectors = partentry.last_lba - partentry.first_lba + 1; + pa.flags = partentry.flags; + pa.entryOffset = start + (idx * entrySize); + const typeOfPartentry = new DataView(partentry.type.slice(0, 0x4).buffer, 0).getUint32(0, true); + if (efiType.hasOwnProperty(typeOfPartentry)) { + pa.type = efiType[typeOfPartentry]; + } else { + pa.type = typeOfPartentry.toString(16); + } let nullIndex = Array.from(partentry.name).findIndex((element, index) => index % 2 === 0 && element === 0); let nameWithoutNull = partentry.name.slice(0, nullIndex); let decodedName = new TextDecoder('utf-16').decode(nameWithoutNull); pa.name = decodedName; - // if pa.type == "EFI_UNUSED": - // continue + if (pa.type == "EFI_UNUSED") + continue; this.partentries[pa.name] = pa; } this.totalsectors = this.header.first_usable_lba + this.header.last_usable_lba; return true; } + + + patch(data, partitionName="boot", active=true) { + for (const sectorSize of [512, 4096]) { + const result = this.parse(data, sectorSize); + if (result) { + for (const rname in this.partentries) { + if (partitionName.toLowerCase() === rname.toLowerCase()) { + const partition = this.partentries[rname]; + const sdata = data.slice(partition.entryOffset, partition.entryOffset+this.header.part_entry_size); + const partentry = new gptPartition(sdata); + let flags = partentry.flags; + if (active) { + flags |= AB_PARTITION_ATTR_SLOT_ACTIVE << (AB_FLAG_OFFSET*8); + } else { + flags |= AB_PARTITION_ATTR_UNBOOTABLE << (AB_FLAG_OFFSET*9) + } + partentry.flags = flags; + let pdata = partentry.create(); + return [ pdata, partition.entryOffset ]; + } + } + break; + } + } + return [ null, null ]; + } + + + fixGptCrc(data) { + const partentry_size = this.header.num_part_entries * this.header.part_entry_size; + const partentry_offset = this.header.part_entry_start_lba * this.sectorSize; + const partdata = data.slice(partentry_offset, partentry_offset + partentry_size); + const headeroffset = this.header.current_lba * this.sectorSize; + let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); + headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(Array.from(partdata)), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(new Array(4).fill(0)), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(Array.from(headerdata)), true))); + data.splice(headeroffset, this.header.header_size, headerdata); + return data; + } } diff --git a/QDL/qdl.js b/QDL/qdl.js index fbfedd1..4d99cfe 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -37,7 +37,7 @@ export class qdlDevice { * or mode = firehose then don't need to connect */ - async flasbBlob(partitionName) { + async flashBlob(partitionName) { let startSector = 0; let dp = await this.firehose?.detectPartition(partitionName); if (dp[0]) { @@ -53,7 +53,6 @@ export class qdlDevice { return false; } startSector = partition.sector; - //console.log(`startSector of ${partitionName} is ${startSector}`); if (await this.firehose.cmdProgram(lun, startSector, "")) { console.log(`Wrote to startSector: ${startSector}`); } else { @@ -81,6 +80,7 @@ export class qdlDevice { } } } + async getActiveSlot() { const luns = this.firehose?.getLuns(); @@ -103,6 +103,19 @@ export class qdlDevice { } //} } + + + async setActvieSlot(slot) { + try { + await this.firehose.cmdSetActiveSlot(slot); + return true; + } catch (error) { + console.error(`Error while setting active slot: ${error}`) + return false; + } + } + + async reset() { try { let resp = await this.doconnect(); @@ -112,10 +125,11 @@ export class qdlDevice { console.log("mode from uploadloader:", mode); } await this.firehose?.configure(0); - await this.erase("cache"); + //await this.erase("cache"); + await this.flashBlob("boot"); await this.firehose?.cmdReset(); } catch (error) { console.error(error); } } -} +} \ No newline at end of file diff --git a/package.json b/package.json index 1b27635..975356d 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "comlink": "^4.4.1", "eslint": "8.40.0", "eslint-config-next": "13.4.1", + "js-crc32": "^1.0.1", "jssha": "^3.3.1", "next": "13.4.1", "next-plausible": "^3.10.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b974344..39da8e1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: eslint-config-next: specifier: 13.4.1 version: 13.4.1(eslint@8.40.0)(typescript@5.1.6) + js-crc32: + specifier: ^1.0.1 + version: 1.0.1 jssha: specifier: ^3.3.1 version: 3.3.1 @@ -2533,6 +2536,11 @@ packages: resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==} hasBin: true + /js-crc32@1.0.1: + resolution: {integrity: sha512-1Lj65x3vOd0SnuNsCY8EtLf531mTSDJKGBbSJfYDcRkDDVoPAtulzzqaWiZGUo9JvLKovaVEKdnyE3UospUg/g==} + engines: {node: '>=0.8'} + dev: false + /js-sdsl@4.4.2: resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} dev: false From c5c72259313c1e3b53b667aa8ca83022dee8b753 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 25 Feb 2024 04:44:34 -0500 Subject: [PATCH 017/112] remove releaseinterface --- QDL/usblib.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/QDL/usblib.js b/QDL/usblib.js index b44e2b7..6b0423b 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -68,12 +68,6 @@ export class usbClass { try { await this.device?.open(); await this.device?.selectConfiguration(1); - try { - await this.device?.releaseInterface(0); - } catch (error) { - console.log(error); - console.log("can't release interface"); - } await this.device?.claimInterface(this.device.configuration.interfaces[0].interfaceNumber); } catch (error) { throw error; From fedf8df22d271986117e4123ab0395029988a6a4 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 25 Feb 2024 05:31:10 -0500 Subject: [PATCH 018/112] cleanup --- QDL/firehose.js | 2 +- QDL/gpt.js | 8 +- QDL/qdl.js | 86 ++++++++++++++++---- QDL/usblib.js | 205 +++++++++++++++--------------------------------- 4 files changed, 139 insertions(+), 162 deletions(-) diff --git a/QDL/firehose.js b/QDL/firehose.js index b764326..ea26342 100644 --- a/QDL/firehose.js +++ b/QDL/firehose.js @@ -452,7 +452,7 @@ export class Firehose { bytesToWrite -= wlen; pos += wlen; await this.cdc._usbWrite(new Uint8Array(0), null, true, true); - console.log(`Finished: ${Math.floor(pos/total)*100}%`); + console.log(`Progress: ${Math.floor(pos/total)*100}%`); } const res = await this.waitForData(); //const info = this.xml.getLog(res); diff --git a/QDL/gpt.js b/QDL/gpt.js index 14a2186..88ce408 100644 --- a/QDL/gpt.js +++ b/QDL/gpt.js @@ -1,5 +1,5 @@ const { containsBytes } = require("./utils"); -const crc32 = require("crc-32"); +const CRC32 = require("crc-32"); const AB_FLAG_OFFSET = 6; const AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2); @@ -306,9 +306,9 @@ export class gpt { const partdata = data.slice(partentry_offset, partentry_offset + partentry_size); const headeroffset = this.header.current_lba * this.sectorSize; let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); - headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(Array.from(partdata)), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(new Array(4).fill(0)), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, crc32(Array.from(headerdata)), true))); + headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(partdata)), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(new Array(4).fill(0)), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(headerdata)), true))); data.splice(headeroffset, this.header.header_size, headerdata); return data; } diff --git a/QDL/qdl.js b/QDL/qdl.js index 4d99cfe..d97be79 100644 --- a/QDL/qdl.js +++ b/QDL/qdl.js @@ -3,17 +3,21 @@ import { Sahara } from "./sahara" import { Firehose } from "./firehose" import { loadFileFromLocal } from "./utils"; +// TODO: reset from sahara mode + export class qdlDevice { cdc; sahara; + mode; constructor() { + this.mode = ""; this.cdc = new usbClass(); this.sahara = new Sahara(this.cdc); this.firehose = new Firehose(this.cdc); } - async doconnect() { + async connectToSahara() { while (!this.cdc.connected){ await this.cdc?.connect(); if (this.cdc.connected){ @@ -22,6 +26,7 @@ export class qdlDevice { let resp = await this.sahara?.connect(); if (resp.hasOwnProperty("mode")){ let mode = resp["mode"]; + this.mode = mode; console.log("Mode detected:", mode); return resp; } @@ -33,11 +38,13 @@ export class qdlDevice { return {"mode" : "error"}; } - /** TODO: check for connected to sahara - * or mode = firehose then don't need to connect - */ async flashBlob(partitionName) { + if (this.mode !== "firehose") { + // TODO: auto connect to sahara + console.error("Please try again, must be in command mode to flash") + return false; + } let startSector = 0; let dp = await this.firehose?.detectPartition(partitionName); if (dp[0]) { @@ -53,6 +60,7 @@ export class qdlDevice { return false; } startSector = partition.sector; + console.log(`Writing to partition ${partitionName}: startSector ${partition.sector} including ${partition.sectors} sectors`); if (await this.firehose.cmdProgram(lun, startSector, "")) { console.log(`Wrote to startSector: ${startSector}`); } else { @@ -60,9 +68,16 @@ export class qdlDevice { } } } + return true; } + async erase(partitionName) { + if (this.mode !== "firehose") { + // TODO: auto connect to sahara + console.error("Please try again, must be in command mode to erase") + return false; + } let luns = this.firehose.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; for (const lun of luns) { @@ -71,7 +86,7 @@ export class qdlDevice { break; if (guidGpt.partentries.hasOwnProperty(partitionName)) { const partition = guidGpt.partentries[partitionName]; - console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors: ${partition.sectors}`); + console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); await this.firehose.cmdErase(lun, partition.sector, partition.sectors); console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sector count ${partition.sectors}`) } else { @@ -79,10 +94,16 @@ export class qdlDevice { continue; } } + return true; } async getActiveSlot() { + if (this.mode !== "firehose") { + // TODO: auto connect to sahara + console.error("Please try again, must be in command mode to get active slot") + return false; + } const luns = this.firehose?.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; //for (const lun of luns) { @@ -102,10 +123,16 @@ export class qdlDevice { } } //} + return true; } async setActvieSlot(slot) { + if (this.mode !== "firehose") { + // TODO: auto connect to sahara + console.error("Please try again, must be in command mode to set active slot"); + return false; + } try { await this.firehose.cmdSetActiveSlot(slot); return true; @@ -113,23 +140,54 @@ export class qdlDevice { console.error(`Error while setting active slot: ${error}`) return false; } + return true; + } + + + async transferToCmdMode() { + let resp = await this.connectToSahara(); + let mode = resp["mode"]; + if (mode === "sahara") + await this.sahara?.uploadLoader(2); // version 2 + await this.firehose?.configure(0); + this.mode = "firehose"; + return true; } async reset() { + if (this.mode !== "firehose") { + // TODO: auto connect to sahara + console.error("Please try again, must be in command mode reset") + return false; + } try { - let resp = await this.doconnect(); - let mode = resp["mode"]; - if (mode === "sahara") { - let mode = await this.sahara?.uploadLoader(2); // version 2 - console.log("mode from uploadloader:", mode); - } - await this.firehose?.configure(0); - //await this.erase("cache"); - await this.flashBlob("boot"); await this.firehose?.cmdReset(); } catch (error) { console.error(error); } + return true; + } + + + // TODO: run() is for testing, will be deleted so that qdl.js is a module + async run() { + try { + let flashPartition = "boot"; + let erasePartition = "cache"; + + await this.transferToCmdMode(); + + await this.flashBlob(flashPartition); + + await this.erase(erasePartition) + + await this.reset(); + + return true; + } catch (error) { + console.error(error); + return false; + } } } \ No newline at end of file diff --git a/QDL/usblib.js b/QDL/usblib.js index 6b0423b..a8dd517 100644 --- a/QDL/usblib.js +++ b/QDL/usblib.js @@ -1,158 +1,77 @@ -import { concatUint8Array, sleep } from "./utils"; +export class structHelper_io { + data; + direction; -const vendorID = 0x05c6; -const productID = 0x9008; -const QDL_USB_CLASS = 0xff; - -export class UsbError extends Error { - constructor(message) { - super(message); - this.name = "UsbError"; + constructor(data, pos=0) { + this.pos = pos + this.data = data; } -} - -// TODO: waitforconnect to check for valid device -export class usbClass { - device; - epIn; - epOut; - - _registeredUsbListeners; - constructor() { - this.device = null; - this.epIn = null; - this.epOut = null; - this._registeredUsbListeners = null; - // TODO: auto maxSize - this.maxSize = 512; + dword(littleEndian=true) { + let view = new DataView(this.data.slice(this.pos, this.pos+4).buffer, 0); + this.pos += 4; + return view.getUint32(0, littleEndian); } - get connected() { - return ( - this.device !== null && - this.device.opened && - this.device.configurations[0].interfaces[0].claimed - ); + qword(littleEndian=true) { + let view = new DataView(this.data.slice(this.pos, this.pos+8).buffer, 0); + this.pos += 8; + return view.getBigUint64(0, littleEndian); } +} - async _validateAndConnectDevice() { - let ife = this.device?.configurations[0].interfaces[0].alternates[0]; - if (ife.endpoints.length !== 2) { - throw new UsbError("Attempted to connect to null device"); - } - - this.epIn = null; - this.epOut = null; - - for (let endpoint of ife.endpoints) { - if (endpoint.type !== "bulk") { - throw new UsbError("Interface endpoint is not bulk"); - } - if (endpoint.direction === "in") { - if (this.epIn === null) { - this.epIn = endpoint; - } else { - throw new UsbError("Interface has multiple IN endpoints"); - } - } else if (endpoint.direction === "out") { - if (this.epOut === null) { - this.epOut = endpoint; - } else { - throw new UsbError("Interface has multiple OUT endpoints"); - } - } - } - console.log("Endpoints: in =", this.epIn, ", out =", this.epOut); - - try { - await this.device?.open(); - await this.device?.selectConfiguration(1); - await this.device?.claimInterface(this.device.configuration.interfaces[0].interfaceNumber); - } catch (error) { - throw error; - } +export function packGenerator(elements, littleEndian=true) { + let n = elements.length; + const buffer = new ArrayBuffer(n*4); + const view = new DataView(buffer); + for (let i = 0; i < n; i++){ + view.setUint32(i*4, elements[i], littleEndian); } + return new Uint8Array(view.buffer); +} - async connect() { - console.log("Trying to connect Qualcomm device") - let devices = await navigator.usb.getDevices(); - console.log("Found these USB devices:", devices); - - this.device = await navigator.usb.requestDevice({ - filters: [ - { - vendorID : vendorID, - productID : productID, - classCode : QDL_USB_CLASS, - }, - ], - }); - console.log("USing USB device:", this.device); - - if (!this._registeredUsbListeners){ - console.log("Get in unregistered"); - navigator.usb.addEventListener("connect", async (event) =>{ - console.log("USB device connect:", event.device); - this.device = event.device; - - try { - await this._validateAndConnectDevice(); - } catch (error) { - console.log("Error while connecting to the device"); - } - }); - - this._registeredUsbListeners = true; +export function concatUint8Array(arrays){ + let length = 0; + arrays.forEach(item => { + if (item !== null) + length += item.length; + }); + + let concatArray = new Uint8Array(length); + let offset = 0; + arrays.forEach( item => { + if (item !== null) { + concatArray.set(item, offset); + offset += item.length; } - await this._validateAndConnectDevice(); - } + }); - async _usbRead(resplen=null){ - let respData = new Uint8Array(); - let covered = 0; - if ((resplen === null)) - resplen = this.epIn.packetSize; - - while (covered < resplen) { - try { - let respPacket = await this.device?.transferIn(this.epIn?.endpointNumber, resplen); - respData = concatUint8Array([respData, new Uint8Array(respPacket.data.buffer)]); - resplen = respData.length; - covered += respData.length; - } catch (error) { - console.error(error); - } - } - return respData; - } + return concatArray; +} - async _usbWrite(cmdPacket, pktSize=null, wait=true, force=false) { - let offset = 0; - if (pktSize === null) - if (cmdPacket.length > this.epOut?.packetSize){ - pktSize = this.epOut?.packetSize; - } else { - pktSize = cmdPacket.length; - } +export function containsBytes(subString, array) { + let tArray = new TextDecoder().decode(array); + return tArray.includes(subString); +} - if (cmdPacket.length === 0 && force) - await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); +export function compareStringToBytes(compareString, array) { + let tArray = new TextDecoder().decode(array); + return compareString == tArray; +} - while (offset < cmdPacket.length){ - try { - if (wait){ - await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); - } else { - this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); - await sleep(80); - } - offset += pktSize; - } catch (error) { - console.error(error); - return false; - } - } - return true; - } +export async function loadFileFromLocal() { + const [fileHandle] = await window.showOpenFilePicker(); + const blob = await fileHandle.getFile(); + return new Promise((resolve, reject) => { + let reader = new FileReader(); + reader.onload = () => { + resolve(reader.result); + }; + reader.onerror = () => { + reject(reader.error); + }; + reader.readAsArrayBuffer(blob); + }); } + +export const sleep = ms => new Promise(r => setTimeout(r, ms)); From ed15a1133ff60d1a592a2546ac27657e80e07973 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 02:47:31 -0500 Subject: [PATCH 019/112] add sparse --- {QDL => src/QDL}/detach_driver.py | 0 {QDL => src/QDL}/firehose.js | 28 +++-- {QDL => src/QDL}/gpt.js | 1 + {QDL => src/QDL}/qdl.js | 14 +-- {QDL => src/QDL}/qualcommConfig.js | 0 {QDL => src/QDL}/sahara.js | 0 {QDL => src/QDL}/saharaDefs.js | 0 src/QDL/sprase.js | 193 +++++++++++++++++++++++++++++ {QDL => src/QDL}/usblib.js | 0 {QDL => src/QDL}/utils.js | 0 {QDL => src/QDL}/xmlParser.js | 0 11 files changed, 219 insertions(+), 17 deletions(-) rename {QDL => src/QDL}/detach_driver.py (100%) rename {QDL => src/QDL}/firehose.js (96%) rename {QDL => src/QDL}/gpt.js (99%) rename {QDL => src/QDL}/qdl.js (92%) rename {QDL => src/QDL}/qualcommConfig.js (100%) rename {QDL => src/QDL}/sahara.js (100%) rename {QDL => src/QDL}/saharaDefs.js (100%) create mode 100644 src/QDL/sprase.js rename {QDL => src/QDL}/usblib.js (100%) rename {QDL => src/QDL}/utils.js (100%) rename {QDL => src/QDL}/xmlParser.js (100%) diff --git a/QDL/detach_driver.py b/src/QDL/detach_driver.py similarity index 100% rename from QDL/detach_driver.py rename to src/QDL/detach_driver.py diff --git a/QDL/firehose.js b/src/QDL/firehose.js similarity index 96% rename from QDL/firehose.js rename to src/QDL/firehose.js index ea26342..94c5b08 100644 --- a/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -1,6 +1,7 @@ import { xmlParser } from "./xmlParser" import { concatUint8Array, containsBytes, compareStringToBytes, sleep, loadFileFromLocal } from "./utils" import { gpt } from "./gpt" +import { QCSparse } from "./sparse"; class response { @@ -320,15 +321,21 @@ export class Firehose { } - // display? - // filename not used until I use the navigator.storage, currently choose image file manually - async cmdProgram(physicalPartitionNumber, startSector, fileName) { - let flashImg = new Uint8Array(await loadFileFromLocal()) - const total = flashImg.length; + async cmdProgram(physicalPartitionNumber, startSector, blob) { + let sparse = new QCSparse(blob); + blob = new Uint8Array(blob) + let total = blob.length; + let sparseformat = false + if (sparse.parseFileHeader()) { + sparseformat = true; + total = sparse.getSize(); + } let bytesToWrite = total; let numPartitionSectors = Math.floor(total/this.cfg.SECTOR_SIZE_IN_BYTES); + if (total % this.cfg.SECTOR_SIZE_IN_BYTES !== 0) numPartitionSectors += 1; + const data = `\n` + ` 0) { - const wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); - console.log - let wdata = flashImg.slice(offset, offset + wlen); + let wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); + let wdata; + if (sparseformat) { + wdata = sparse.read(wlen); + } else { + wdata = blob.slice(offset, offset + wlen); + } offset += wlen; bytesToWrite -= wlen; @@ -355,6 +366,7 @@ export class Firehose { console.log(`Progress: ${Math.floor(offset/total)*100}%`); await this.cdc._usbWrite(new Uint8Array(0), null, true, true); } + const wd = await this.waitForData(); const log = this.xml.getLog(wd); const rsp = this.xml.getReponse(wd); diff --git a/QDL/gpt.js b/src/QDL/gpt.js similarity index 99% rename from QDL/gpt.js rename to src/QDL/gpt.js index 88ce408..cf1f1ce 100644 --- a/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -40,6 +40,7 @@ class structHelper { } } +// TODO: remove unecessary const efiType = { 0x00000000 : "EFI_UNUSED", 0x024DEE41 : "EFI_MBR", diff --git a/QDL/qdl.js b/src/QDL/qdl.js similarity index 92% rename from QDL/qdl.js rename to src/QDL/qdl.js index d97be79..4a50d67 100644 --- a/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -39,9 +39,8 @@ export class qdlDevice { } - async flashBlob(partitionName) { + async flashBlob(partitionName, blob) { if (this.mode !== "firehose") { - // TODO: auto connect to sahara console.error("Please try again, must be in command mode to flash") return false; } @@ -49,7 +48,7 @@ export class qdlDevice { let dp = await this.firehose?.detectPartition(partitionName); if (dp[0]) { let lun = dp[1]; - const imgSize = new Uint8Array(await loadFileFromLocal()).length; + const imgSize = blob.size; let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) imgSectors += 1; @@ -61,7 +60,7 @@ export class qdlDevice { } startSector = partition.sector; console.log(`Writing to partition ${partitionName}: startSector ${partition.sector} including ${partition.sectors} sectors`); - if (await this.firehose.cmdProgram(lun, startSector, "")) { + if (await this.firehose.cmdProgram(lun, startSector, blob)) { console.log(`Wrote to startSector: ${startSector}`); } else { console.error("Error writing image"); @@ -74,7 +73,6 @@ export class qdlDevice { async erase(partitionName) { if (this.mode !== "firehose") { - // TODO: auto connect to sahara console.error("Please try again, must be in command mode to erase") return false; } @@ -100,7 +98,6 @@ export class qdlDevice { async getActiveSlot() { if (this.mode !== "firehose") { - // TODO: auto connect to sahara console.error("Please try again, must be in command mode to get active slot") return false; } @@ -129,7 +126,6 @@ export class qdlDevice { async setActvieSlot(slot) { if (this.mode !== "firehose") { - // TODO: auto connect to sahara console.error("Please try again, must be in command mode to set active slot"); return false; } @@ -157,7 +153,6 @@ export class qdlDevice { async reset() { if (this.mode !== "firehose") { - // TODO: auto connect to sahara console.error("Please try again, must be in command mode reset") return false; } @@ -178,7 +173,8 @@ export class qdlDevice { await this.transferToCmdMode(); - await this.flashBlob(flashPartition); + let blob = await loadFileFromLocal(); + await this.flashBlob(flashPartition, blob); await this.erase(erasePartition) diff --git a/QDL/qualcommConfig.js b/src/QDL/qualcommConfig.js similarity index 100% rename from QDL/qualcommConfig.js rename to src/QDL/qualcommConfig.js diff --git a/QDL/sahara.js b/src/QDL/sahara.js similarity index 100% rename from QDL/sahara.js rename to src/QDL/sahara.js diff --git a/QDL/saharaDefs.js b/src/QDL/saharaDefs.js similarity index 100% rename from QDL/saharaDefs.js rename to src/QDL/saharaDefs.js diff --git a/src/QDL/sprase.js b/src/QDL/sprase.js new file mode 100644 index 0000000..b98c8f1 --- /dev/null +++ b/src/QDL/sprase.js @@ -0,0 +1,193 @@ +import { concatUint8Array, loadFileFromLocal } from "./utils"; + + +const FILE_MAGIC = 0xed26ff3a; +const FILE_HEADER_SIZE = 28; +const CHUNK_HEADER_SIZE = 12; + +export const ChunkType = { + Raw : 0xcac1, + Fill : 0xcac2, + Skip : 0xcac3, + Crc32 : 0xcac4, +} + + +export class QCSparse { + constructor(blob) { + this.blob = blob + this.offset = 0; + this.major_version = null; + this.minor_version = null; + this.file_hdr_sz = null; + this.chunk_hdr_sz = null; + this.blk_sz = null; + this.total_blks = null; + this.total_chunks = null; + this.image_checksum = null; + this.blobOffset = 0; + } + + + parseFileHeader() { + let header = this.blob.slice(0, FILE_HEADER_SIZE); + let view = new DataView(header); + + let magic = view.getUint32(0, true); + this.major_version = view.getUint16(4, true); + this.minor_version = view.getUint16(6, true); + this.file_hdr_sz = view.getUint16(8, true); + this.chunk_hdr_sz = view.getUint16(10, true); + this.blk_sz = view.getUint32(12, true); + this.total_blks = view.getUint32(16, true); + this.total_chunks = view.getUint32(20, true); + this.image_checksum = view.getUint32(24, true); + + if (magic != FILE_MAGIC) { + return false; + } + if (this.file_hdr_sz != FILE_MAGIC) { + console.error(`The file header size was expected to be 28, but is ${this.file_hdr_sz}.`); + return false; + } + if (this.chunk_hdr_sz != CHUNK_HEADER_SIZE) { + console.error(`The chunk header size was expected to be 12, but is ${this.chunk_hdr_sz}.`); + return false; + } + console.log("Sparse format detected. USing unpacked iamge."); + return true; + } + + + getChunkSize() { + if (this.total_blks < this.offset) { + console.error("Unmached output blocks"); + return -1; + } + let chunkHeader = this.blob.slice(this.blobOffset, CHUNK_HEADER_SIZE); + let view = new DataView(chunkHeader); + const chunk_type = view.getUint16(0, true); + const chunk_sz = view.getUint32(4, true); + const total_sz = view.getUint32(8, true); + const data_sz = total_sz - 12; + + if (chunk_type == ChunkType.Raw) { + if (data_sz != (chunk_sz*this.blk_sz)) { + console.error("Rase chunk input size does not match output size"); + return -1; + } else { + this.blobOffset += chunk_sz * this.blk_sz; + return chunk_sz * this.blk_sz; + } + } else if (chunk_type == ChunkType.Fill) { + if (data_sz != 4) { + console.error("Fill chunk shoudl have 4 bytes of fill"); + return -1; + } else { + return Math.floor((chunk_sz * this.blk_sz)/4); + } + } else if (chunk_type == ChunkType.Skip) { + return chunk_sz * this.blk_sz; + } else if (chunk_type == ChunkType.Crc32) { + if (data_sz != 4) { + console.error("CRC32 chunk should have 4 bytes of CRC"); + return -1; + } else { + this.blobOffset += 4; + return 0; + } + } else { + console.error("Unknown chunk type"); + return -1; + } + } + + + getSize() { + this.blobOffset += FILE_HEADER_SIZE; + let length = 0, chunk = 0; + while (chunk < this.total_chunks) { + let tlen = this.getChunkSize(); + if (tlen == -1) + break; + length += tlen; + chunk += 1; + } + this.blobOffset = FILE_HEADER_SIZE; + return length; + } + + + unsparse() { + if (this.total_blks < this.offset) { + console.error("Error while unsparsing"); + return -1; + } + let chunkHeader = this.blob.slice(this.blobOffset, CHUNK_HEADER_SIZE); + let view = new DataView(chunkHeader); + const chunk_type = view.getUint16(0, true); + const chunk_sz = view.getUint32(4, true); + const total_sz = view.getUint32(8, true); + const data_sz = total_sz - 12; + + if (chunk_type == ChunkType.Raw) { + if (data_sz != (chunk_sz*this.blk_sz)) { + console.error("Rase chunk input size does not match output size"); + return -1; + } else { + let data = this.blob.slice(this.blobOffset, this.blobOffset += chunk_sz * this.blk_sz); + this.offset += chunk_sz; + return data; + } + } else if (chunk_type == ChunkType.Fill) { + if (data_sz != 4) { + console.error("Fill chunk should have 4 bytes of fill"); + return -1; + } else { + let fill_bin = new Uint8Array(this.blob.slice(this.blobOffset, this.blobOffset += 4)); + const repetitions = Math.floor((chunk_sz * this.blk_sz)/4); + let data; + for (let i = 0; i < repetitions; i++) { + data = concatUint8Array([data, fill_bin]); + } + this.offset += chunk_sz; + return data.buffer; + } + } else if (chunk_type == ChunkType.Skip) { + let data = new ArrayBuffer(chunk_sz*this.blk_sz).fill(0x00); + this.offset += chunk_sz; + return data; + } else if (chunk_type == ChunkType.Crc32) { + if (data_sz != 4) { + console.error("CRC32 chunk should have 4 bytes of CRC"); + return -1; + } else { + this.blobOffset += 4; + return new ArrayBuffer(0); + } + } else { + console.error("Unknown chunk type"); + return -1; + } + } + + + read(length=null) { + let tdata; + if (length === null) + return this.unsparse(); + if (length <= this.tmpdata.length) { + tdata = this.tmpdata.slice(0, length); + this.tmpdata = this.tmpdata.slice(length); + return tdata; + } + while (this.tmpdata.length < length) { + this.tmpdata = concatUint8Array([this.tmpdata, new Uint8Array(this.unsparse())]) + if (length <= this.tmpdata.length) { + tdata = this.tmpdata.slice(0, length); + this.tmpdata = this.tmpdata.slice(length); + return tdata; + } + } + } +} diff --git a/QDL/usblib.js b/src/QDL/usblib.js similarity index 100% rename from QDL/usblib.js rename to src/QDL/usblib.js diff --git a/QDL/utils.js b/src/QDL/utils.js similarity index 100% rename from QDL/utils.js rename to src/QDL/utils.js diff --git a/QDL/xmlParser.js b/src/QDL/xmlParser.js similarity index 100% rename from QDL/xmlParser.js rename to src/QDL/xmlParser.js From c6f960dbf793e84197392ddd2af94f428edeac43 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 04:56:20 -0500 Subject: [PATCH 020/112] big cleanup --- src/QDL/firehose.js | 275 +++++++++++++++++++++----------------- src/QDL/gpt.js | 94 +++++++------ src/QDL/qdl.js | 32 ++--- src/QDL/qualcommConfig.js | 3 - src/QDL/sahara.js | 209 +++++++++++++++-------------- src/QDL/saharaDefs.js | 8 -- src/QDL/usblib.js | 203 +++++++++++++++++++--------- 7 files changed, 461 insertions(+), 363 deletions(-) delete mode 100644 src/QDL/qualcommConfig.js diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 94c5b08..9c2a02d 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -13,6 +13,7 @@ class response { } } + class cfg { constructor() { this.TargetName = ""; @@ -34,6 +35,7 @@ class cfg { } } + export class Firehose { cdc; xml; @@ -46,9 +48,71 @@ export class Firehose { this.luns = []; } - async configure(lvl) { + + getStatus(resp) { + if (resp.hasOwnProperty("value")) { + let value = resp["value"]; + if (value == "ACK" || value == "true" ) { + return true; + } else { + return false; + } + } + return true; + } + + + async xmlSend(data, wait=true) { + let dataToSend = new TextEncoder().encode(data).slice(0, this.cfg.MaxXMLSizeInBytes); + await this.cdc?.write(dataToSend, null, wait); + + let rData = new Uint8Array(); // response data in bytes + let counter = 0; + let timeout = 0; + + while (!(containsBytes(" timeout) + break; + } + rData = concatUint8Array([rData, tmp]); + } catch (error) { + console.error(error); + } + } + + try { + const resp = this.xml.getReponse(rData); // input is Uint8Array + const status = this.getStatus(resp); + if (resp.hasOwnProperty("rawmode")) { + if (resp["rawmode"] == "false") { + let log = this.xml.getLog(rData); + return new response(status, rData, "", log) + } + } else { + if (status) { + if (containsBytes("log value=", rData)) { + let log = this.xml.getLog(rData); + return new response(status, rData, "", log); + } + return new response(status, rData); + } + } + } catch (error) { + console.error(error); + } + return new response(true, rData); + } + + + async configure() { if (this.cfg.SECTOR_SIZE_IN_BYTES == 0) this.cfg.SECTOR_SIZE_IN_BYTES = 4096 + let connectCmd = `` + `` + `` - // TODO: Transfer connectCmd to Uint8Array - //let rsp = await this.xmlSend(connectCmd, false); - //return true; let rsp = await this.xmlSend(connectCmd, false); if (rsp === null || !rsp.resp) { if (rsp.error == "") { - return await this.configure(lvl+1); + return await this.configure(); } } else { await this.parseStorage(); @@ -131,9 +192,9 @@ export class Firehose { } } } - return { resp: val.resp, data : res}; + return new response(val.resp, res); } - return { resp : val.resp, data : val.data}; + return new response(val.resp, val.data); } else { if (!val.error !== null && !val.error !== "") { console.error("failed to open SDCC device"); @@ -143,72 +204,16 @@ export class Firehose { } - async xmlSend(data, wait=true) { - let dataToSend = new TextEncoder().encode(data).slice(0, this.cfg.MaxXMLSizeInBytes); - await this.cdc?._usbWrite(dataToSend, null, wait); - let rData = new Uint8Array(); // response data in bytes - let counter = 0; - let timeout = 0; - while (!(containsBytes(" timeout) - break; - } - rData = concatUint8Array([rData, tmp]); - } catch (error) { - console.error(error); - } - } - try { - const resp = this.xml.getReponse(rData); // input is Uint8Array - const status = this.getStatus(resp); - if (resp.hasOwnProperty("rawmode")) { - if (resp["rawmode"] == "false") { - let log = this.xml.getLog(rData); - return new response(status, rData, "", log) - } - } else { - if (status) { - if (containsBytes("log value=", rData)) { - let log = this.xml.getLog(rData); - //return { resp : status, data : rData, log : log, error : "" }; // TODO: getLog() - return new response(status, rData, "", log); - } - return new response(status, rData); - } - } - } catch (error) { - console.error(error); - } - return new response(true, rData); - } - - - async cmdReset() { - let data = ""; - let val = await this.xmlSend(data); - if (val.resp) { - console.log("Reset succeeded"); - return true; - } else { - console.error("Reset failed"); - return false; - } - } - - async detectPartition(partitionName) { let fPartitions = {}; for (const lun of this.luns) { - const lunName = "Lun" + lun.toString(); - fPartitions[lunName] = [] - const gptNumPartEntries = 0; - const gptPartEntrySize = 0; - const gptPartEntryStartLba = 0; + + const lunName = "Lun" + lun.toString(); + fPartitions[lunName] = [] + const gptNumPartEntries = 0; + const gptPartEntrySize = 0; + const gptPartEntryStartLba = 0; + let [ data, guidGpt ] = await this.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); if (guidGpt === null) { break; @@ -235,23 +240,29 @@ export class Firehose { console.error(resp.error); return [null, null]; } - let data = resp.data; + + let data = resp.data; let guidGpt = new gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + try { const header = guidGpt.parseHeader(data, this.cfg.SECTOR_SIZE_IN_BYTES); if (containsBytes("EFI PART", header.signature)) { - const gptSize = (header.part_entry_start_lba * this.cfg.SECTOR_SIZE_IN_BYTES) + + const gptSize = (header.part_entry_start_lba * this.cfg.SECTOR_SIZE_IN_BYTES) + (header.num_part_entries * header.part_entry_size); - let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES); + let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES); + if (gptSize % this.cfg.SECTOR_SIZE_IN_BYTES != 0) sectors += 1; if (sectors === 0) sectors = 64; if (sectors > 64) sectors = 64; + data = await this.cmdReadBuffer(lun, 0, sectors); + if (compareStringToBytes("", data.data)) return [null, null]; + guidGpt.parse(data.data, this.cfg.SECTOR_SIZE_IN_BYTES); return [data.data, guidGpt]; } else { @@ -265,27 +276,29 @@ export class Firehose { async cmdReadBuffer(physicalPartitionNumber, startSector, numPartitionSectors) { - //let prog = 0; const data = `\n` - let rsp = await this.xmlSend(data); + + let rsp = await this.xmlSend(data); let resData = new Uint8Array(); - if (!rsp.resp){ + + if (!rsp.resp) { return rsp } else { let bytesToRead = this.cfg.SECTOR_SIZE_IN_BYTES * numPartitionSectors; - let total = bytesToRead; // for progress bar while (bytesToRead > 0) { - let tmp = await this.cdc._usbRead(Math.min(this.cdc.maxSize, bytesToRead)); - const size = tmp.length; - bytesToRead -= size; - resData = concatUint8Array([resData, tmp]); + let tmp = await this.cdc.read(Math.min(this.cdc.maxSize, bytesToRead)); + const size = tmp.length; + bytesToRead-= size; + resData = concatUint8Array([resData, tmp]); } - const wd = await this.waitForData(); - const info = this.xml.getLog(wd); - rsp = this.xml.getReponse(wd); + + const wd = await this.waitForData(); + const info = this.xml.getLog(wd); + rsp = this.xml.getReponse(wd); + if (rsp.hasOwnProperty("value")) { if (rsp["value"] !== "ACK") { return new response(false, resData, info); @@ -304,10 +317,11 @@ export class Firehose { async waitForData() { - let tmp = new Uint8Array(); + let tmp = new Uint8Array(); let timeout = 0; + while (!containsBytes("response value", tmp)) { - let res = await this.cdc._usbRead(); + let res = await this.cdc.read(); if (compareStringToBytes("", res)) { timeout += 1; if (timeout === 4){ @@ -322,15 +336,17 @@ export class Firehose { async cmdProgram(physicalPartitionNumber, startSector, blob) { - let sparse = new QCSparse(blob); - blob = new Uint8Array(blob) - let total = blob.length; - let sparseformat = false + let sparse = new QCSparse(blob); + blob = new Uint8Array(blob) + let total = blob.length; + let sparseformat = false + if (sparse.parseFileHeader()) { - sparseformat = true; - total = sparse.getSize(); + sparseformat = true; + total = sparse.getSize(); } - let bytesToWrite = total; + + let bytesToWrite = total; let numPartitionSectors = Math.floor(total/this.cfg.SECTOR_SIZE_IN_BYTES); if (total % this.cfg.SECTOR_SIZE_IN_BYTES !== 0) @@ -342,19 +358,21 @@ export class Firehose { ` physical_partition_number=\"${physicalPartitionNumber}\"` + ` start_sector=\"${startSector}\" />\n`; - let rsp = await this.xmlSend(data); - let offset = 0; + let rsp = await this.xmlSend(data); + let offset = 0; + if (rsp.resp) { while (bytesToWrite > 0) { let wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); let wdata; + if (sparseformat) { wdata = sparse.read(wlen); } else { wdata = blob.slice(offset, offset + wlen); } - offset += wlen; - bytesToWrite -= wlen; + offset += wlen; + bytesToWrite -= wlen; if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + @@ -362,12 +380,13 @@ export class Firehose { const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); wdata = concatUint8Array([wdata, fillArray]); } - await this.cdc._usbWrite(wdata); + + await this.cdc.write(wdata); console.log(`Progress: ${Math.floor(offset/total)*100}%`); - await this.cdc._usbWrite(new Uint8Array(0), null, true, true); + await this.cdc.write(new Uint8Array(0), null, true, true); } - const wd = await this.waitForData(); + const wd = await this.waitForData(); const log = this.xml.getLog(wd); const rsp = this.xml.getReponse(wd); if (rsp.hasOwnProperty("value")) { @@ -385,9 +404,10 @@ export class Firehose { async cmdSetActiveSlot(slot) { - slot = slot.toLowerCase(); - const luns = this.getLuns(); + slot = slot.toLowerCase(); + const luns = this.getLuns(); let partSlots = {}; + if (slot == "a") { partSlots["_a"] = true; partSlots["_b"] = false; @@ -398,23 +418,26 @@ export class Firehose { console.error("Only slots a or b are accepted. Aborting."); return false; } + for (const lun of luns) { const [ data, guidGpt ] = await this.getGpt(lun, 0, 0, 0); if (guidGpt === null) break; for (const partitionName in guidGpt.partentries) { - const gp = new gpt(); - slot = partitionName.toLowerCase().slice(-2); + const gp = new gpt(); + slot = partitionName.toLowerCase().slice(-2); if (slot === "a" || slot === "b") { const [ pdata, pOffset ] = gp.patch(data, partitionName, partSlots[slot]); data.splice(pOffset, pdata.length, pdata); let wdata = gp.fixGptCrc(data); + if (wdata !== null) { const startSectorPath = Math.floor(pOffset/this.cfg.SECTOR_SIZE_IN_BYTES); const byteOffsetPatch = pOffset % this.cfg.SECTOR_SIZE_IN_BYTES; - const headerOffset = gp.header.current_lba * gp.sectorSize; - const startSectorHdr = Math.floor(headerOffset/this.cfg.SECTOR_SIZE_IN_BYTES); - const header = wdata.slice(startSectorHdr, startSectorHdr+gp.header.header_size); + const headerOffset = gp.header.current_lba * gp.sectorSize; + const startSectorHdr = Math.floor(headerOffset/this.cfg.SECTOR_SIZE_IN_BYTES); + const header = wdata.slice(startSectorHdr, startSectorHdr+gp.header.header_size); + await this.cmdPatch(lun, startSectorPath, byteOffsetPatch, pdata, pdata.length); await this.cmdPatch(lun, headerOffset, 0, header, pdata.length); } @@ -453,25 +476,26 @@ export class Firehose { ` physical_partition_number=\"${physicalPartitionNumber}\"` + ` start_sector=\"${startSector}\" />\n`; - let rsp = await this.xmlSend(data) - let empty = new Uint8Array(this.cfg.MaxPayloadSizeToTargetInBytes).fill(0x00); - let pos = 0, bytesToWrite = this.cfg.SECTOR_SIZE_IN_BYTES * numPartitionSectors; + let rsp = await this.xmlSend(data) + let empty = new Uint8Array(this.cfg.MaxPayloadSizeToTargetInBytes).fill(0x00); + let pos = 0, bytesToWrite = this.cfg.SECTOR_SIZE_IN_BYTES * numPartitionSectors; const total = bytesToWrite; + if (rsp.resp) { while (bytesToWrite > 0) { let wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeToTargetInBytes); - await this.cdc._usbWrite(empty.slice(0, wlen)); + await this.cdc.write(empty.slice(0, wlen)); bytesToWrite -= wlen; pos += wlen; - await this.cdc._usbWrite(new Uint8Array(0), null, true, true); + await this.cdc.write(new Uint8Array(0), null, true, true); console.log(`Progress: ${Math.floor(pos/total)*100}%`); } - const res = await this.waitForData(); - //const info = this.xml.getLog(res); - const response = this.xml.getReponse(res); + + const res = await this.waitForData(); + const response = this.xml.getReponse(res); if (response.hasOwnProperty("value")) { if (response["value"] !== "ACK") { - console.error("ERROR") + console.error("ERROR: receiving ACK trying to erase"); return false; } } else { @@ -482,17 +506,18 @@ export class Firehose { console.log("Finish erasing"); return true; } + + async cmdReset() { + let data = ""; + let val = await this.xmlSend(data); - getStatus(resp) { - if (resp.hasOwnProperty("value")) { - let value = resp["value"]; - if (value == "ACK" || value == "true" ) { - return true; - } else { - return false; - } + if (val.resp) { + console.log("Reset succeeded"); + return true; + } else { + console.error("Reset failed"); + return false; } - return true; } } diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index cf1f1ce..760667f 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -40,7 +40,6 @@ class structHelper { } } -// TODO: remove unecessary const efiType = { 0x00000000 : "EFI_UNUSED", 0x024DEE41 : "EFI_MBR", @@ -187,27 +186,27 @@ class gptPartition { class partf { - unique = new Uint8Array(); - firstLba = 0; - lastLba = 0; - flags = 0; - sector = 0; - sectors = 0; - type = null; - name = ""; + firstLba = 0; + lastLba = 0; + flags = 0; + sector = 0; + sectors = 0; entryOffset = 0; + type = null; + name = ""; + unique = new Uint8Array(); } export class gpt { constructor(numPartEntries=0, partEntrySize=0, partEntryStartLba=0) { - this.numPartEntries = numPartEntries; - this.partEntrySize = partEntrySize; - this.partEntryStartLba = partEntryStartLba; - this.totalSectors = null; - this.header = null; - this.sectorSize = null; - this.partentries = {}; + this.numPartEntries = numPartEntries; + this.partEntrySize = partEntrySize; + this.partEntryStartLba = partEntryStartLba; + this.totalSectors = null; + this.header = null; + this.sectorSize = null; + this.partentries = {}; } parseHeader(gptData, sectorSize=512){ @@ -215,14 +214,16 @@ export class gpt { } parse(gptData, sectorSize=512) { - this.header = new gptHeader(gptData.slice(sectorSize, sectorSize + 0x5C)); + this.header = new gptHeader(gptData.slice(sectorSize, sectorSize + 0x5C)); this.sectorSize = sectorSize; + if (!containsBytes("EFI PART", this.header.signature)) return false; if (this.header.revision != 0x10000) { console.error("Unknown GPT revision."); return false; } + let start; if (this.partEntryStartLba != 0) { start = self.partEntryStartLba; @@ -230,43 +231,51 @@ export class gpt { start = this.header.part_entry_start_lba * sectorSize; } - let entrySize = this.header.part_entry_size; - this.partentries = {}; - - let numPartEntries = this.header.num_part_entries; - + let entrySize = this.header.part_entry_size; + this.partentries = {}; + let numPartEntries = this.header.num_part_entries; for (let idx=0; idx < numPartEntries; idx++) { const data = gptData.slice(start + (idx * entrySize), start + (idx * entrySize) + entrySize); if (new DataView(data.slice(16,32).buffer, 0).getUint16(0, true) == 0) break; - let partentry = new gptPartition(data); - let pa = new partf(); - const guid1 = new DataView(partentry.unique.slice(0, 0x4).buffer, 0).getUint32(0, true); - const guid2 = new DataView(partentry.unique.slice(0x4, 0x6).buffer, 0).getUint16(0, true); - const guid3 = new DataView(partentry.unique.slice(0x6, 0x8).buffer, 0).getUint16(0, true); - const guid4 = new DataView(partentry.unique.slice(0x8, 0xA).buffer, 0).getUint16(0, true); - const guid5 = Array.from(partentry.unique.subarray(0xA, 0x10)) + let partentry = new gptPartition(data); + let pa = new partf(); + const guid1 = new DataView(partentry.unique.slice(0, 0x4).buffer, 0).getUint32(0, true); + const guid2 = new DataView(partentry.unique.slice(0x4, 0x6).buffer, 0).getUint16(0, true); + const guid3 = new DataView(partentry.unique.slice(0x6, 0x8).buffer, 0).getUint16(0, true); + const guid4 = new DataView(partentry.unique.slice(0x8, 0xA).buffer, 0).getUint16(0, true); + const guid5 = Array.from(partentry.unique.subarray(0xA, 0x10)) .map(byte => byte.toString(16).padStart(2, '0')) .join(''); - pa.unique = `${guid1.toString(16).padStart(8, '0')}-${guid2.toString(16).padStart(4, '0')}-${guid3.toString(16).padStart(4, '0')}-${guid4.toString(16).padStart(4, '0')}-${guid5}`; - pa.sector = partentry.first_lba; - pa.sectors = partentry.last_lba - partentry.first_lba + 1; - pa.flags = partentry.flags; - pa.entryOffset = start + (idx * entrySize); + pa.unique =`${guid1.toString(16).padStart(8, '0')}- + ${guid2.toString(16).padStart(4, '0')}- + ${guid3.toString(16).padStart(4, '0')}- + ${guid4.toString(16).padStart(4, '0')}- + ${guid5}`; + pa.sector = partentry.first_lba; + pa.sectors = partentry.last_lba - partentry.first_lba + 1; + pa.flags = partentry.flags; + pa.entryOffset = start + (idx * entrySize); const typeOfPartentry = new DataView(partentry.type.slice(0, 0x4).buffer, 0).getUint32(0, true); + if (efiType.hasOwnProperty(typeOfPartentry)) { pa.type = efiType[typeOfPartentry]; } else { pa.type = typeOfPartentry.toString(16); } - let nullIndex = Array.from(partentry.name).findIndex((element, index) => index % 2 === 0 && element === 0); + + let nullIndex = Array.from(partentry.name).findIndex( + (element, index) => index % 2 === 0 && element === 0 + ); let nameWithoutNull = partentry.name.slice(0, nullIndex); - let decodedName = new TextDecoder('utf-16').decode(nameWithoutNull); - pa.name = decodedName; + let decodedName = new TextDecoder('utf-16').decode(nameWithoutNull); + pa.name = decodedName; + if (pa.type == "EFI_UNUSED") continue; + this.partentries[pa.name] = pa; } this.totalsectors = this.header.first_usable_lba + this.header.last_usable_lba; @@ -302,11 +311,12 @@ export class gpt { fixGptCrc(data) { - const partentry_size = this.header.num_part_entries * this.header.part_entry_size; - const partentry_offset = this.header.part_entry_start_lba * this.sectorSize; - const partdata = data.slice(partentry_offset, partentry_offset + partentry_size); - const headeroffset = this.header.current_lba * this.sectorSize; - let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); + const partentry_size = this.header.num_part_entries * this.header.part_entry_size; + const partentry_offset = this.header.part_entry_start_lba * this.sectorSize; + const partdata = data.slice(partentry_offset, partentry_offset + partentry_size); + const headeroffset = this.header.current_lba * this.sectorSize; + let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); + headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(partdata)), true))); headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(new Array(4).fill(0)), true))); headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(headerdata)), true))); diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 4a50d67..2252453 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -3,7 +3,6 @@ import { Sahara } from "./sahara" import { Firehose } from "./firehose" import { loadFileFromLocal } from "./utils"; -// TODO: reset from sahara mode export class qdlDevice { cdc; @@ -48,7 +47,7 @@ export class qdlDevice { let dp = await this.firehose?.detectPartition(partitionName); if (dp[0]) { let lun = dp[1]; - const imgSize = blob.size; + const imgSize = blob.byteLength; let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) imgSectors += 1; @@ -59,9 +58,9 @@ export class qdlDevice { return false; } startSector = partition.sector; - console.log(`Writing to partition ${partitionName}: startSector ${partition.sector} including ${partition.sectors} sectors`); + console.log(`Flashing ${partitionName}...`); if (await this.firehose.cmdProgram(lun, startSector, blob)) { - console.log(`Wrote to startSector: ${startSector}`); + console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); } else { console.error("Error writing image"); } @@ -84,9 +83,9 @@ export class qdlDevice { break; if (guidGpt.partentries.hasOwnProperty(partitionName)) { const partition = guidGpt.partentries[partitionName]; - console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); + console.log(`Erasing ${partitionName}...`) await this.firehose.cmdErase(lun, partition.sector, partition.sectors); - console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sector count ${partition.sectors}`) + console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sectors ${partition.sectors}`) } else { console.log(`Couldn't erase partition ${partitionName}. Either wrong type or not in lun ${lun}`); continue; @@ -110,17 +109,11 @@ export class qdlDevice { return "" for (const partitionName in guidGpt.partentries) { const slot = partitionName.slice(-2); - if (slot == "_a") { - return "a"; - } else if (slot == "b") { - return "b"; - } else { - console.error("Can't detect slot A or B"); - return "" - } + return (slot === "a") ? "a" : "b"; } + console.error("Can't detect slot A or B"); + return ""; //} - return true; } @@ -136,16 +129,15 @@ export class qdlDevice { console.error(`Error while setting active slot: ${error}`) return false; } - return true; } - async transferToCmdMode() { + async toCmdMode() { let resp = await this.connectToSahara(); let mode = resp["mode"]; if (mode === "sahara") await this.sahara?.uploadLoader(2); // version 2 - await this.firehose?.configure(0); + await this.firehose?.configure(); this.mode = "firehose"; return true; } @@ -171,7 +163,7 @@ export class qdlDevice { let flashPartition = "boot"; let erasePartition = "cache"; - await this.transferToCmdMode(); + await this.toCmdMode(); let blob = await loadFileFromLocal(); await this.flashBlob(flashPartition, blob); @@ -186,4 +178,4 @@ export class qdlDevice { return false; } } -} \ No newline at end of file +} diff --git a/src/QDL/qualcommConfig.js b/src/QDL/qualcommConfig.js deleted file mode 100644 index 547318c..0000000 --- a/src/QDL/qualcommConfig.js +++ /dev/null @@ -1,3 +0,0 @@ -export const msmids = { - 0x05F0E1: "MSM8996Pro" // SnapDragon 821, MSM8996SG -} diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 42c48a1..0d6d3d8 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -11,49 +11,121 @@ export class Sahara { mode; constructor(cdc) { - this.cdc = cdc; - this.pktSize = null; - this.version = null; - this.ch = new CommandHandler(); + this.cdc = cdc; + this.pktSize = null; + this.version = null; + this.ch = new CommandHandler(); + // TODO: change to auto upload Loader this.programmer = "0005f0e100000000_b155b8bf19297f47_fhprg_peek.bin"; - this.id = null; - this.mode = ""; + this.id = null; + this.mode = ""; } async connect() { try { - let v = await this.cdc?._usbRead(0xC * 0x4); + let v = await this.cdc?.read(0xC * 0x4); let v_text = new TextDecoder("utf-8").decode(v); if (v.length > 1){ if (v[0] == 0x01){ let pkt = this.ch.pkt_cmd_hdr(v); if (pkt.cmd === cmd_t.SAHARA_HELLO_REQ) { - let rsp = this.ch.pkt_hello_req(v); + let rsp = this.ch.pkt_hello_req(v); this.pktSize = rsp.cmd_packet_length; this.version = rsp.version; return { "mode" : "sahara", "cmd" : cmd_t.SAHARA_HELLO_REQ, "data" : rsp }; - // TODO: probably don't need from here downward till end of this func - } else if (v_text.includes("") - this.cdc._usbwrite(data); - let resp = await this.cdc._usbRead(); - let resp_text = new TextDecoder().decode(resp); - if (resp_text.includes("= 0 || done){ let resp = await this.getResponse(); let cmd @@ -91,7 +166,6 @@ export class Sahara { return "" } } - // TODO: Probably not necessary if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)) { if (cmd == cmd_t.SAHARA_64BIT_MEMORY_READ_DATA) if (loop == 0) @@ -106,16 +180,18 @@ export class Sahara { console.error("Unknown sahara id"); return "error"; } + loop += 1; let dataOffset = pkt.data_offset; - let dataLen = pkt.data_len; + let dataLen = pkt.data_len; if (dataOffset + dataLen > programmer.length) { const fillerArray = new Uint8Array(dataOffset+dataLen-programmer.length).fill(0xff); programmer = concatUint8Array([programmer, fillerArray]); } let dataToSend = programmer.slice(dataOffset, dataOffset+dataLen); // Uint8Array - await this.cdc?._usbWrite(dataToSend); + await this.cdc?.write(dataToSend); datalen -= dataLen; + } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { let pkt = resp["data"]; if (pkt.image_tx_status == status_t.SAHARA_STATUS_SUCCESS){ @@ -130,13 +206,15 @@ export class Sahara { } } catch (error) { console.error(error); + return "error"; } return this.mode; } + async cmdDone(){ const toSendData = packGenerator([cmd_t.SAHARA_DONE_REQ, 0x8]); - if (await this.cdc._usbWrite(toSendData)) { + if (await this.cdc.write(toSendData)) { let res = await this.getResponse(); for (let i = 0; i < 500; i += 1) continue; @@ -159,79 +237,4 @@ export class Sahara { } return false; } - - async enterCommandMode(version=2) { - if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND)){ - return false; - } - let res = await this.getResponse(); - if (res.hasOwnProperty("cmd")){ - if (res["cmd"] === cmd_t.SAHARA_END_TRANSFER){ - if (res.hasOwnProperty("data")){ - return false; - } - } else if (res["cmd"] === cmd_t.SAHARA_CMD_READY){ - return true; - } - } - return false; - } - - async getResponse() { - try { - let data = await this.cdc?._usbRead(); - let data_text = new TextDecoder('utf-8').decode(data.data); - if (data.length == 0){ - return {}; - } else if (data_text.includes(" { - if (item !== null) - length += item.length; - }); - - let concatArray = new Uint8Array(length); - let offset = 0; - arrays.forEach( item => { - if (item !== null) { - concatArray.set(item, offset); - offset += item.length; + async connect() { + console.log("Trying to connect Qualcomm device") + let devices = await navigator.usb.getDevices(); + console.log("Found these USB devices:", devices); + + this.device = await navigator.usb.requestDevice({ + filters: [ + { + vendorID : vendorID, + productID : productID, + classCode : QDL_USB_CLASS, + }, + ], + }); + console.log("USing USB device:", this.device); + + if (!this._registeredUsbListeners){ + console.log("Get in unregistered"); + navigator.usb.addEventListener("connect", async (event) =>{ + console.log("USB device connect:", event.device); + this.device = event.device; + + try { + await this._validateAndConnectDevice(); + } catch (error) { + console.log("Error while connecting to the device"); + } + }); + + this._registeredUsbListeners = true; } - }); + await this._validateAndConnectDevice(); + } - return concatArray; -} + async read(resplen=null){ + let respData = new Uint8Array(); + let covered = 0; + if ((resplen === null)) + resplen = this.epIn.packetSize; -export function containsBytes(subString, array) { - let tArray = new TextDecoder().decode(array); - return tArray.includes(subString); -} + while (covered < resplen) { + try { + let respPacket = await this.device?.transferIn(this.epIn?.endpointNumber, resplen); + respData = concatUint8Array([respData, new Uint8Array(respPacket.data.buffer)]); + resplen = respData.length; + covered += respData.length; + } catch (error) { + console.error(error); + } + } + return respData; + } -export function compareStringToBytes(compareString, array) { - let tArray = new TextDecoder().decode(array); - return compareString == tArray; -} + async write(cmdPacket, pktSize=null, wait=true, force=false) { + let offset = 0; + if (pktSize === null) + if (cmdPacket.length > this.epOut?.packetSize){ + pktSize = this.epOut?.packetSize; + } else { + pktSize = cmdPacket.length; + } -export async function loadFileFromLocal() { - const [fileHandle] = await window.showOpenFilePicker(); - const blob = await fileHandle.getFile(); - return new Promise((resolve, reject) => { - let reader = new FileReader(); - reader.onload = () => { - resolve(reader.result); - }; - reader.onerror = () => { - reject(reader.error); - }; - reader.readAsArrayBuffer(blob); - }); -} + if (cmdPacket.length === 0 && force) + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); -export const sleep = ms => new Promise(r => setTimeout(r, ms)); + while (offset < cmdPacket.length){ + try { + if (wait) { + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + } else { + this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); + await sleep(80); + } + offset += pktSize; + } catch (error) { + console.error(error); + return false; + } + } + return true; + } +} From 2d67a92dd06ec74dd138445ec5bbeb48542a5d5d Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 04:58:16 -0500 Subject: [PATCH 021/112] cleanup saharadefs --- src/QDL/saharaDefs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QDL/saharaDefs.js b/src/QDL/saharaDefs.js index 3a24412..5e65eb8 100644 --- a/src/QDL/saharaDefs.js +++ b/src/QDL/saharaDefs.js @@ -152,4 +152,4 @@ export class CommandHandler { data_len : st.dword(), } } -} \ No newline at end of file +} From 5a084fdf4bf67256a7b198c698f009f281b2e294 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 18:44:02 -0500 Subject: [PATCH 022/112] automate usb packet maxsize --- src/QDL/usblib.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 54b3c3d..fbdf1f3 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -24,6 +24,7 @@ export class usbClass { this.epIn = null; this.epOut = null; this._registeredUsbListeners = null; + this.maxSize = 512; } get connected() { @@ -60,6 +61,7 @@ export class usbClass { throw new UsbError("Interface has multiple OUT endpoints"); } } + this.maxSize = this.epIn.packetSize; } console.log("Endpoints: in =", this.epIn, ", out =", this.epOut); From 097a33dde8dc771a9d5706eca8af9a05c1809417 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 22:35:22 -0500 Subject: [PATCH 023/112] fix getactiveslot --- src/QDL/gpt.js | 4 ++-- src/QDL/qdl.js | 27 ++++++++++++++++++--------- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index 760667f..59103af 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -1,8 +1,8 @@ const { containsBytes } = require("./utils"); const CRC32 = require("crc-32"); -const AB_FLAG_OFFSET = 6; -const AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2); +export const AB_FLAG_OFFSET = 6; +export const AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2); const AB_PARTITION_ATTR_UNBOOTABLE = (0x1 << 7); class structHelper { diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 2252453..3ce5584 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -2,6 +2,7 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" import { loadFileFromLocal } from "./utils"; +import * as gpt from "./gpt" export class qdlDevice { @@ -100,20 +101,28 @@ export class qdlDevice { console.error("Please try again, must be in command mode to get active slot") return false; } + const luns = this.firehose?.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; - //for (const lun of luns) { - const lun = luns[0]; - let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); - if (guidGpt === null) - return "" - for (const partitionName in guidGpt.partentries) { - const slot = partitionName.slice(-2); - return (slot === "a") ? "a" : "b"; + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + + if (guidGpt === null) + return "" + + for (const partitionName in guidGpt.partentries) { + const slot = partitionName.slice(-2); + const partition = guidGpt.partentries[partitionName]; + const active = (((partition.flags >> (gpt.AB_FLAG_OFFSET*8))&0xff) & gpt.AB_PARTITION_ATTR_SLOT_ACTIVE) == gpt.AB_PARTITION_ATTR_SLOT_ACTIVE; + if (slot == "_a" && active) { + return "a"; + } else if (slot == "_b" && active) { + return "b"; + } + } } console.error("Can't detect slot A or B"); return ""; - //} } From 1f9362ed6162646a0107b25d5236f49f95ccf041 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Mon, 26 Feb 2024 22:52:34 -0500 Subject: [PATCH 024/112] import only used from gpt.js --- src/QDL/qdl.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 3ce5584..8188e40 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -2,7 +2,7 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" import { loadFileFromLocal } from "./utils"; -import * as gpt from "./gpt" +import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" export class qdlDevice { @@ -113,7 +113,7 @@ export class qdlDevice { for (const partitionName in guidGpt.partentries) { const slot = partitionName.slice(-2); const partition = guidGpt.partentries[partitionName]; - const active = (((partition.flags >> (gpt.AB_FLAG_OFFSET*8))&0xff) & gpt.AB_PARTITION_ATTR_SLOT_ACTIVE) == gpt.AB_PARTITION_ATTR_SLOT_ACTIVE; + const active = (((partition.flags >> (AB_FLAG_OFFSET*8))&0xff) & AB_PARTITION_ATTR_SLOT_ACTIVE) == AB_PARTITION_ATTR_SLOT_ACTIVE; if (slot == "_a" && active) { return "a"; } else if (slot == "_b" && active) { From 527ab41fa279ba958463f85685fda3aa2340aad0 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Tue, 27 Feb 2024 01:07:25 -0500 Subject: [PATCH 025/112] refactor --- {src/QDL => QDL}/detach_driver.py | 0 {src/QDL => QDL}/firehose.js | 2 +- {src/QDL => QDL}/gpt.js | 0 {src/QDL => QDL}/qdl.js | 40 ++++++++++++++++++++++++++----- {src/QDL => QDL}/sahara.js | 0 {src/QDL => QDL}/saharaDefs.js | 0 {src/QDL => QDL}/sprase.js | 0 {src/QDL => QDL}/usblib.js | 0 {src/QDL => QDL}/utils.js | 0 {src/QDL => QDL}/xmlParser.js | 0 10 files changed, 35 insertions(+), 7 deletions(-) rename {src/QDL => QDL}/detach_driver.py (100%) rename {src/QDL => QDL}/firehose.js (100%) rename {src/QDL => QDL}/gpt.js (100%) rename {src/QDL => QDL}/qdl.js (82%) rename {src/QDL => QDL}/sahara.js (100%) rename {src/QDL => QDL}/saharaDefs.js (100%) rename {src/QDL => QDL}/sprase.js (100%) rename {src/QDL => QDL}/usblib.js (100%) rename {src/QDL => QDL}/utils.js (100%) rename {src/QDL => QDL}/xmlParser.js (100%) diff --git a/src/QDL/detach_driver.py b/QDL/detach_driver.py similarity index 100% rename from src/QDL/detach_driver.py rename to QDL/detach_driver.py diff --git a/src/QDL/firehose.js b/QDL/firehose.js similarity index 100% rename from src/QDL/firehose.js rename to QDL/firehose.js index 9c2a02d..59ef351 100644 --- a/src/QDL/firehose.js +++ b/QDL/firehose.js @@ -506,8 +506,8 @@ export class Firehose { console.log("Finish erasing"); return true; } - + async cmdReset() { let data = ""; let val = await this.xmlSend(data); diff --git a/src/QDL/gpt.js b/QDL/gpt.js similarity index 100% rename from src/QDL/gpt.js rename to QDL/gpt.js diff --git a/src/QDL/qdl.js b/QDL/qdl.js similarity index 82% rename from src/QDL/qdl.js rename to QDL/qdl.js index 8188e40..9c7f534 100644 --- a/src/QDL/qdl.js +++ b/QDL/qdl.js @@ -1,7 +1,6 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" -import { loadFileFromLocal } from "./utils"; import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" @@ -17,6 +16,7 @@ export class qdlDevice { this.firehose = new Firehose(this.cdc); } + async connectToSahara() { while (!this.cdc.connected){ await this.cdc?.connect(); @@ -95,6 +95,33 @@ export class qdlDevice { return true; } + + async getDevicePartitions() { + const partitions = []; + const luns = this.firehose?.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + try { + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + + if (guidGpt === null) + return []; + for (const partitionName in guidGpt.partentries) { + let partition = partitionName; + if (partitionName.endsWith("_a") || partitionName.endsWith("_b")) + partition = partitionName.substring(0, partitionName.length-2); + if (partitions.includes(partition)) + continue; + partitions.push(partition); + } + } + return partitions; + } catch (error) { + console.error(error); + return []; + } + } + async getActiveSlot() { if (this.mode !== "firehose") { @@ -106,10 +133,8 @@ export class qdlDevice { let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; for (const lun of luns) { let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); - if (guidGpt === null) return "" - for (const partitionName in guidGpt.partentries) { const slot = partitionName.slice(-2); const partition = guidGpt.partentries[partitionName]; @@ -174,10 +199,13 @@ export class qdlDevice { await this.toCmdMode(); - let blob = await loadFileFromLocal(); - await this.flashBlob(flashPartition, blob); + //let blob = await loadFileFromLocal(); + //await this.flashBlob(flashPartition, blob); + + //await this.erase(erasePartition) - await this.erase(erasePartition) + let partitions = await this.getDevicePartitions(); + console.log("Partitions:", partitions); await this.reset(); diff --git a/src/QDL/sahara.js b/QDL/sahara.js similarity index 100% rename from src/QDL/sahara.js rename to QDL/sahara.js diff --git a/src/QDL/saharaDefs.js b/QDL/saharaDefs.js similarity index 100% rename from src/QDL/saharaDefs.js rename to QDL/saharaDefs.js diff --git a/src/QDL/sprase.js b/QDL/sprase.js similarity index 100% rename from src/QDL/sprase.js rename to QDL/sprase.js diff --git a/src/QDL/usblib.js b/QDL/usblib.js similarity index 100% rename from src/QDL/usblib.js rename to QDL/usblib.js diff --git a/src/QDL/utils.js b/QDL/utils.js similarity index 100% rename from src/QDL/utils.js rename to QDL/utils.js diff --git a/src/QDL/xmlParser.js b/QDL/xmlParser.js similarity index 100% rename from src/QDL/xmlParser.js rename to QDL/xmlParser.js From d30222b7c79e9a0916f0df68291b3e73f87339f8 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Tue, 27 Feb 2024 01:07:58 -0500 Subject: [PATCH 026/112] move folder --- {QDL => src/QDL}/detach_driver.py | 0 {QDL => src/QDL}/firehose.js | 0 {QDL => src/QDL}/gpt.js | 0 {QDL => src/QDL}/qdl.js | 0 {QDL => src/QDL}/sahara.js | 0 {QDL => src/QDL}/saharaDefs.js | 0 {QDL => src/QDL}/sprase.js | 0 {QDL => src/QDL}/usblib.js | 0 {QDL => src/QDL}/utils.js | 0 {QDL => src/QDL}/xmlParser.js | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename {QDL => src/QDL}/detach_driver.py (100%) rename {QDL => src/QDL}/firehose.js (100%) rename {QDL => src/QDL}/gpt.js (100%) rename {QDL => src/QDL}/qdl.js (100%) rename {QDL => src/QDL}/sahara.js (100%) rename {QDL => src/QDL}/saharaDefs.js (100%) rename {QDL => src/QDL}/sprase.js (100%) rename {QDL => src/QDL}/usblib.js (100%) rename {QDL => src/QDL}/utils.js (100%) rename {QDL => src/QDL}/xmlParser.js (100%) diff --git a/QDL/detach_driver.py b/src/QDL/detach_driver.py similarity index 100% rename from QDL/detach_driver.py rename to src/QDL/detach_driver.py diff --git a/QDL/firehose.js b/src/QDL/firehose.js similarity index 100% rename from QDL/firehose.js rename to src/QDL/firehose.js diff --git a/QDL/gpt.js b/src/QDL/gpt.js similarity index 100% rename from QDL/gpt.js rename to src/QDL/gpt.js diff --git a/QDL/qdl.js b/src/QDL/qdl.js similarity index 100% rename from QDL/qdl.js rename to src/QDL/qdl.js diff --git a/QDL/sahara.js b/src/QDL/sahara.js similarity index 100% rename from QDL/sahara.js rename to src/QDL/sahara.js diff --git a/QDL/saharaDefs.js b/src/QDL/saharaDefs.js similarity index 100% rename from QDL/saharaDefs.js rename to src/QDL/saharaDefs.js diff --git a/QDL/sprase.js b/src/QDL/sprase.js similarity index 100% rename from QDL/sprase.js rename to src/QDL/sprase.js diff --git a/QDL/usblib.js b/src/QDL/usblib.js similarity index 100% rename from QDL/usblib.js rename to src/QDL/usblib.js diff --git a/QDL/utils.js b/src/QDL/utils.js similarity index 100% rename from QDL/utils.js rename to src/QDL/utils.js diff --git a/QDL/xmlParser.js b/src/QDL/xmlParser.js similarity index 100% rename from QDL/xmlParser.js rename to src/QDL/xmlParser.js From b786d9e1687be72ee84bde5cc56e22d21fbb0dc0 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 03:44:39 -0500 Subject: [PATCH 027/112] integrate --- package.json | 2 +- pnpm-lock.yaml | 17 +- src/QDL/blob.js | 27 ++ src/QDL/firehose.js | 4 +- src/QDL/gpt.js | 1 - src/QDL/image.js | 15 + src/QDL/manifest.js | 95 ++++++ src/QDL/manifest.test.js | 75 +++++ src/QDL/progress.js | 42 +++ src/QDL/qdl.js | 483 +++++++++++++++++++------------ src/QDL/qdlDevice.js | 243 ++++++++++++++++ src/QDL/{sprase.js => sparse.js} | 0 src/QDL/usblib.js | 10 +- src/app/Flash.jsx | 5 +- 14 files changed, 822 insertions(+), 197 deletions(-) create mode 100644 src/QDL/blob.js create mode 100644 src/QDL/image.js create mode 100644 src/QDL/manifest.js create mode 100644 src/QDL/manifest.test.js create mode 100644 src/QDL/progress.js create mode 100644 src/QDL/qdlDevice.js rename src/QDL/{sprase.js => sparse.js} (100%) diff --git a/package.json b/package.json index 975356d..076637d 100644 --- a/package.json +++ b/package.json @@ -17,9 +17,9 @@ "android-fastboot": "github:commaai/fastboot.js#c3ec6fe3c96a48dab46e23d0c8c861af15b2144a", "autoprefixer": "10.4.14", "comlink": "^4.4.1", + "crc-32": "^1.2.2", "eslint": "8.40.0", "eslint-config-next": "13.4.1", - "js-crc32": "^1.0.1", "jssha": "^3.3.1", "next": "13.4.1", "next-plausible": "^3.10.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 39da8e1..eaa6712 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,15 +14,15 @@ dependencies: comlink: specifier: ^4.4.1 version: 4.4.1 + crc-32: + specifier: ^1.2.2 + version: 1.2.2 eslint: specifier: 8.40.0 version: 8.40.0 eslint-config-next: specifier: 13.4.1 version: 13.4.1(eslint@8.40.0)(typescript@5.1.6) - js-crc32: - specifier: ^1.0.1 - version: 1.0.1 jssha: specifier: ^3.3.1 version: 3.3.1 @@ -1459,6 +1459,12 @@ packages: path-type: 4.0.0 dev: true + /crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: false + /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2536,11 +2542,6 @@ packages: resolution: {integrity: sha512-oVhqoRDaBXf7sjkll95LHVS6Myyyb1zaunVwk4Z0+WPSW4gjS0pl01zYKHScTuyEhQsFxV5L4DR5r+YqSyqyyg==} hasBin: true - /js-crc32@1.0.1: - resolution: {integrity: sha512-1Lj65x3vOd0SnuNsCY8EtLf531mTSDJKGBbSJfYDcRkDDVoPAtulzzqaWiZGUo9JvLKovaVEKdnyE3UospUg/g==} - engines: {node: '>=0.8'} - dev: false - /js-sdsl@4.4.2: resolution: {integrity: sha512-dwXFwByc/ajSV6m5bcKAPwe4yDDF6D614pxmIi5odytzxRlwqF6nwoiCek80Ixc7Cvma5awClxrzFtxCQvcM8w==} dev: false diff --git a/src/QDL/blob.js b/src/QDL/blob.js new file mode 100644 index 0000000..f36551f --- /dev/null +++ b/src/QDL/blob.js @@ -0,0 +1,27 @@ +'use client' + +export async function download(url) { + const response = await fetch(url, { mode: 'cors' }) + const reader = response.body.getReader() + const contentLength = +response.headers.get('Content-Length') + console.debug('[blob] Downloading', url, contentLength) + + const chunks = [] + let processed = 0 + while (true) { + const { done, value } = await reader.read() + if (done) break + chunks.push(value) + processed += value.length + } + + const blob = new Blob(chunks) + console.debug('[blob] Downloaded', url, blob.size) + if (blob.size !== contentLength) console.warn('[blob] Download size mismatch', { + url, + expected: contentLength, + actual: blob.size, + }) + + return blob +} diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 59ef351..89d37ef 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -335,7 +335,7 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob) { + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress) { let sparse = new QCSparse(blob); blob = new Uint8Array(blob) let total = blob.length; @@ -373,6 +373,8 @@ export class Firehose { } offset += wlen; bytesToWrite -= wlen; + onProgress(offset/total); + if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index 59103af..f7df906 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -162,7 +162,6 @@ class gptPartition { create() { - // TODO: finish create function let buffer = new ArrayBuffer(16 + 16 + 8 + 8 + 8 + 72); let view = new DataView(buffer); let offset = 0; diff --git a/src/QDL/image.js b/src/QDL/image.js new file mode 100644 index 0000000..370fc33 --- /dev/null +++ b/src/QDL/image.js @@ -0,0 +1,15 @@ +import { useEffect, useRef } from 'react' + +import * as Comlink from 'comlink' + +export function useImageWorker() { + const apiRef = useRef() + + useEffect(() => { + const worker = new Worker(new URL('../workers/image.worker.js', import.meta.url)) + apiRef.current = Comlink.wrap(worker) + return () => worker.terminate() + }, []) + + return apiRef +} diff --git a/src/QDL/manifest.js b/src/QDL/manifest.js new file mode 100644 index 0000000..2f6c3d5 --- /dev/null +++ b/src/QDL/manifest.js @@ -0,0 +1,95 @@ +/** + * Represents a partition image defined in the AGNOS manifest. + * + * Image archives can be retrieved from {@link archiveUrl}. + */ +export class Image { + /** + * Partition name + * @type {string} + */ + name + + /** + * SHA-256 checksum of the image, encoded as a hex string + * @type {string} + */ + checksum + /** + * Size of the unpacked image in bytes + * @type {number} + */ + size + /** + * Whether the image is sparse + * @type {boolean} + */ + sparse + + /** + * Name of the image file + * @type {string} + */ + fileName + + /** + * Name of the image archive file + * @type {string} + */ + archiveFileName + /** + * URL of the image archive + * @type {string} + */ + archiveUrl + + constructor(json) { + this.name = json.name + this.sparse = json.sparse + + if (this.name === 'system') { + this.checksum = json.alt.hash + this.fileName = `${this.name}-skip-chunks-${json.hash_raw}.img` + this.archiveUrl = json.alt.url + this.size = json.alt.size + } else { + this.checksum = json.hash + this.fileName = `${this.name}-${json.hash_raw}.img` + this.archiveUrl = json.url + this.size = json.size + } + + this.archiveFileName = this.archiveUrl.split('/').pop() + } +} + +/** + * @param {string} text + * @returns {Image[]} + */ +export function createManifest(text) { + const expectedPartitions = ['aop', 'devcfg', 'xbl', 'xbl_config', 'abl', 'boot', 'system'] + const partitions = JSON.parse(text).map((image) => new Image(image)) + + // Sort into consistent order + partitions.sort((a, b) => expectedPartitions.indexOf(a.name) - expectedPartitions.indexOf(b.name)) + + // Check that all partitions are present + // TODO: should we prevent flashing if there are extra partitions? + const missingPartitions = expectedPartitions.filter((name) => !partitions.some((image) => image.name === name)) + if (missingPartitions.length > 0) { + throw new Error(`Manifest is missing partitions: ${missingPartitions.join(', ')}`) + } + + return partitions +} + +/** + * @param {string} url + * @returns {Promise} + */ +export function getManifest(url) { + return fetch(url) + .then((response) => response.text()) + .then(createManifest) +} diff --git a/src/QDL/manifest.test.js b/src/QDL/manifest.test.js new file mode 100644 index 0000000..b7ec3f8 --- /dev/null +++ b/src/QDL/manifest.test.js @@ -0,0 +1,75 @@ +import { expect, test, vi } from 'vitest' + +import * as Comlink from 'comlink' + +import config from '../config' +import { getManifest } from './manifest' + +async function getImageWorker() { + let imageWorker + + vi.mock('comlink') + vi.mocked(Comlink.expose).mockImplementation(worker => { + imageWorker = worker + imageWorker.init() + }) + + await import('./../workers/image.worker') + + return imageWorker +} + +for (const [branch, manifestUrl] of Object.entries(config.manifests)) { + describe(`${branch} manifest`, async () => { + const imageWorkerFileHandler = { + getFile: vi.fn(), + createWritable: vi.fn().mockImplementation(() => ({ + write: vi.fn(), + close: vi.fn(), + })), + } + + global.navigator = { + storage: { + getDirectory: () => ({ + getFileHandle: () => imageWorkerFileHandler, + }) + } + } + + const imageWorker = await getImageWorker() + + const images = await getManifest(manifestUrl) + + // Check all images are present + expect(images.length).toBe(7) + + for (const image of images) { + describe(`${image.name} image`, async () => { + test('xz archive', () => { + expect(image.archiveFileName, 'archive to be in xz format').toContain('.xz') + expect(image.archiveUrl, 'archive url to be in xz format').toContain('.xz') + }) + + if (image.name === 'system') { + test('alt image', () => { + expect(image.sparse, 'system image to be sparse').toBe(true) + expect(image.fileName, 'system image to be skip chunks').toContain('-skip-chunks-') + expect(image.archiveUrl, 'system image to point to skip chunks').toContain('-skip-chunks-') + }) + } + + test('image and checksum', async () => { + imageWorkerFileHandler.getFile.mockImplementation(async () => { + const response = await fetch(image.archiveUrl) + expect(response.ok, 'to be uploaded').toBe(true) + + return response.blob() + }) + + await imageWorker.unpackImage(image) + }, 8 * 60 * 1000) + }) + } + }) +} diff --git a/src/QDL/progress.js b/src/QDL/progress.js new file mode 100644 index 0000000..ef209ee --- /dev/null +++ b/src/QDL/progress.js @@ -0,0 +1,42 @@ +/** + * Create a set of callbacks that can be used to track progress of a multistep process. + * + * @param {(number[]|number)} steps + * @param {progressCallback} onProgress + * @returns {(progressCallback)[]} + */ +export function createSteps(steps, onProgress) { + const stepWeights = typeof steps === 'number' ? Array(steps).fill(1) : steps + + const progressParts = Array(stepWeights.length).fill(0) + const totalSize = stepWeights.reduce((total, weight) => total + weight, 0) + + function updateProgress() { + const weightedAverage = stepWeights.reduce((acc, weight, idx) => { + return acc + progressParts[idx] * weight + }, 0) + onProgress(weightedAverage / totalSize) + } + + return stepWeights.map((weight, idx) => (progress) => { + if (progressParts[idx] !== progress) { + progressParts[idx] = progress + updateProgress() + } + }) +} + +/** + * Iterate over a list of steps while reporting progress. + * @template T + * @param {(number[]|T[])} steps + * @param {progressCallback} onProgress + * @returns {([T, progressCallback])[]} + */ +export function withProgress(steps, onProgress) { + const callbacks = createSteps( + steps.map(step => typeof step === 'number' ? step : step.size || step.length || 1), + onProgress, + ) + return steps.map((step, idx) => [step, callbacks[idx]]) +} diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 9c7f534..ec2b691 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -1,218 +1,337 @@ -import { usbClass } from "./usblib" -import { Sahara } from "./sahara" -import { Firehose } from "./firehose" -import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" - - -export class qdlDevice { - cdc; - sahara; - mode; - - constructor() { - this.mode = ""; - this.cdc = new usbClass(); - this.sahara = new Sahara(this.cdc); - this.firehose = new Firehose(this.cdc); +'use client' +import { useEffect, useRef, useState } from 'react' + +import { qdlDevice } from './qdlDevice.js' +import * as Comlink from 'comlink' +import { usePlausible } from 'next-plausible' + +import config from '@/config' +import { download } from '@/QDL/blob' +import { useImageWorker } from '@/QDL/image' +import { createManifest } from '@/QDL/manifest' +import { withProgress } from '@/QDL/progress' + +/** + * @typedef {import('./manifest.js').Image} Image + */ + +export const Step = { + INITIALIZING: 0, + READY: 1, + CONNECTING: 2, + DOWNLOADING: 3, + UNPACKING: 4, + FLASHING: 6, + ERASING: 7, + DONE: 8, +} + +export const Error = { + UNKNOWN: -1, + NONE: 0, + UNRECOGNIZED_DEVICE: 1, + LOST_CONNECTION: 2, + DOWNLOAD_FAILED: 3, + UNPACK_FAILED: 4, + CHECKSUM_MISMATCH: 5, + FLASH_FAILED: 6, + ERASE_FAILED: 7, + REQUIREMENTS_NOT_MET: 8, +} + +function isRecognizedDevice(partitions) { + // check we have the expected partitions to make sure it's a comma three + const expectedPartitions = [ + "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", + "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", + "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", + "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", + "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", + "xbl_config" + ] + if (!partitions.every(partition => expectedPartitions.includes(partition))) { + console.error('[QDL] Unrecognised device (partitions)', partitions) + return false } + return true; +} - async connectToSahara() { - while (!this.cdc.connected){ - await this.cdc?.connect(); - if (this.cdc.connected){ - console.log("Device detected"); - try { - let resp = await this.sahara?.connect(); - if (resp.hasOwnProperty("mode")){ - let mode = resp["mode"]; - this.mode = mode; - console.log("Mode detected:", mode); - return resp; - } - } catch (error) { - console.error(error); - } - } - } - return {"mode" : "error"}; +export function useQdl() { + const [step, _setStep] = useState(Step.INITIALIZING) + const [message, _setMessage] = useState('') + const [progress, setProgress] = useState(0) + const [error, _setError] = useState(Error.NONE) + + const [connected, setConnected] = useState(false) + const [serial, setSerial] = useState(null) + + const [onContinue, setOnContinue] = useState(null) + const [onRetry, setOnRetry] = useState(null) + + const imageWorker = useImageWorker() + const qdl = useRef(new qdlDevice()) + + /** @type {React.RefObject} */ + const manifest = useRef(null) + + const plausible = usePlausible() + + function setStep(step) { + _setStep(step) + } + + function setMessage(message = '') { + if (message) console.info('[QDL]', message) + _setMessage(message) } + function setError(error) { + _setError(error) + } + useEffect(() => { + setProgress(-1) + setMessage() - async flashBlob(partitionName, blob) { - if (this.mode !== "firehose") { - console.error("Please try again, must be in command mode to flash") - return false; + if (error) return + if (!imageWorker.current) { + console.debug('[QDL] Waiting for image worker') + return } - let startSector = 0; - let dp = await this.firehose?.detectPartition(partitionName); - if (dp[0]) { - let lun = dp[1]; - const imgSize = blob.byteLength; - let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); - if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) - imgSectors += 1; - if (partitionName.toLowerCase() !== "gpt") { - const partition = dp[2]; - if (imgSectors > partition.sectors) { - console.error("partition has fewer sectors compared to the flashing image"); - return false; + + switch (step) { + case Step.INITIALIZING: { + // Check that the browser supports WebUSB + if (typeof navigator.usb === 'undefined') { + console.error('[QDL] WebUSB not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break + } + + // Check that the browser supports Web Workers + if (typeof Worker === 'undefined') { + console.error('[QDL] Web Workers not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break } - startSector = partition.sector; - console.log(`Flashing ${partitionName}...`); - if (await this.firehose.cmdProgram(lun, startSector, blob)) { - console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); - } else { - console.error("Error writing image"); + + // Check that the browser supports Storage API + if (typeof Storage === 'undefined') { + console.error('[QDL] Storage API not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break } + + // TODO: change manifest once alt image is in release + imageWorker.current?.init() + .then(() => download(config.manifests['master'])) + .then(blob => blob.text()) + .then(text => { + manifest.current = createManifest(text) + + // sanity check + if (manifest.current.length === 0) { + throw 'Manifest is empty' + } + + console.debug('[QDL] Loaded manifest', manifest.current) + setStep(Step.READY) + }) + .catch((err) => { + console.error('[QDL] Initialization error', err) + setError(Error.UNKNOWN) + }) + break } - } - return true; - } + case Step.READY: { + // wait for user interaction (we can't use WebUSB without user event) + setOnContinue(() => () => { + setOnContinue(null) + setStep(Step.CONNECTING) + }) + break + } - async erase(partitionName) { - if (this.mode !== "firehose") { - console.error("Please try again, must be in command mode to erase") - return false; - } - let luns = this.firehose.getLuns(); - let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; - for (const lun of luns) { - let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); - if (guidGpt === null) - break; - if (guidGpt.partentries.hasOwnProperty(partitionName)) { - const partition = guidGpt.partentries[partitionName]; - console.log(`Erasing ${partitionName}...`) - await this.firehose.cmdErase(lun, partition.sector, partition.sectors); - console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sectors ${partition.sectors}`) - } else { - console.log(`Couldn't erase partition ${partitionName}. Either wrong type or not in lun ${lun}`); - continue; + case Step.CONNECTING: { + qdl.current.waitForConnect() + .then(() => { + console.info('[QDL] Connected') + return qdl.current.getDevicePartitions() + .then((partitions) => { + + const recognized = isRecognizedDevice(partitions) + console.debug('[QDL] Device info', { recognized, partitions}) + + if (!recognized) { + setError(Error.UNRECOGNIZED_DEVICE) + return + } + + //setSerial(deviceInfo['serialno'] || 'unknown') + setConnected(true) + plausible('device-connected') + setStep(Step.DOWNLOADING) + }) + .catch((err) => { + console.error('[QDL] Error getting device information', err) + setError(Error.UNKNOWN) + }) + }) + .catch((err) => { + console.error('[QDL] Connection lost', err) + setError(Error.LOST_CONNECTION) + setConnected(false) + }) + + qdl.current.connect() + .catch((err) => { + console.error('[QDL] Connection error', err) + setStep(Step.READY) + }) + break } - } - return true; - } + case Step.DOWNLOADING: { + setProgress(0) - async getDevicePartitions() { - const partitions = []; - const luns = this.firehose?.getLuns(); - let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; - try { - for (const lun of luns) { - let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); - - if (guidGpt === null) - return []; - for (const partitionName in guidGpt.partentries) { - let partition = partitionName; - if (partitionName.endsWith("_a") || partitionName.endsWith("_b")) - partition = partitionName.substring(0, partitionName.length-2); - if (partitions.includes(partition)) - continue; - partitions.push(partition); + async function downloadImages() { + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + setMessage(`Downloading ${image.name}`) + await imageWorker.current.downloadImage(image, Comlink.proxy(onProgress)) + } } + + downloadImages() + .then(() => { + console.debug('[QDL] Downloaded all images') + setStep(Step.UNPACKING) + }) + .catch((err) => { + console.error('[QDL] Download error', err) + setError(Error.DOWNLOAD_FAILED) + }) + break } - return partitions; - } catch (error) { - console.error(error); - return []; - } - } - - async getActiveSlot() { - if (this.mode !== "firehose") { - console.error("Please try again, must be in command mode to get active slot") - return false; - } + case Step.UNPACKING: { + setProgress(0) - const luns = this.firehose?.getLuns(); - let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; - for (const lun of luns) { - let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); - if (guidGpt === null) - return "" - for (const partitionName in guidGpt.partentries) { - const slot = partitionName.slice(-2); - const partition = guidGpt.partentries[partitionName]; - const active = (((partition.flags >> (AB_FLAG_OFFSET*8))&0xff) & AB_PARTITION_ATTR_SLOT_ACTIVE) == AB_PARTITION_ATTR_SLOT_ACTIVE; - if (slot == "_a" && active) { - return "a"; - } else if (slot == "_b" && active) { - return "b"; + async function unpackImages() { + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + setMessage(`Unpacking ${image.name}`) + await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) + } } + + unpackImages() + .then(() => { + console.debug('[QDL] Unpacked all images') + setStep(Step.FLASHING) + }) + .catch((err) => { + console.error('[QDL] Unpack error', err) + if (err.startsWith('Checksum mismatch')) { + setError(Error.CHECKSUM_MISMATCH) + } else { + setError(Error.UNPACK_FAILED) + } + }) + break } - } - console.error("Can't detect slot A or B"); - return ""; - } + case Step.FLASHING: { + setProgress(0) - async setActvieSlot(slot) { - if (this.mode !== "firehose") { - console.error("Please try again, must be in command mode to set active slot"); - return false; - } - try { - await this.firehose.cmdSetActiveSlot(slot); - return true; - } catch (error) { - console.error(`Error while setting active slot: ${error}`) - return false; - } - } + async function flashDevice() { + const currentSlot = await qdl.current.getActiveSlot(); + if (!['a', 'b'].includes(currentSlot)) { + throw `Unknown current slot ${currentSlot}` + } + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + const fileHandle = await imageWorker.current.getImage(image) + const blob = await fileHandle.getFile() - async toCmdMode() { - let resp = await this.connectToSahara(); - let mode = resp["mode"]; - if (mode === "sahara") - await this.sahara?.uploadLoader(2); // version 2 - await this.firehose?.configure(); - this.mode = "firehose"; - return true; - } + if (image.sparse) { + setMessage(`Erasing ${image.name}`) + await qdl.current.erase(image.name) + } + setMessage(`Flashing ${image.name}`) + await qdl.current.flashBlob(image.name, blob, onProgress) + } + console.debug('[QDL] Flashed all partitions') + const otherSlot = currentSlot === 'a' ? 'b' : 'a' + setMessage(`Changing slot to ${otherSlot}`) + await qdl.current.setActvieSlot(otherSlot); + } - async reset() { - if (this.mode !== "firehose") { - console.error("Please try again, must be in command mode reset") - return false; - } - try { - await this.firehose?.cmdReset(); - } catch (error) { - console.error(error); - } - return true; - } + flashDevice() + .then(() => { + console.debug('[QDL] Flash complete') + setStep(Step.ERASING) + }) + .catch((err) => { + console.error('[QDL] Flashing error', err) + setError(Error.FLASH_FAILED) + }) + break + } + + case Step.ERASING: { + setProgress(0) + async function eraseDevice() { + setMessage('Erasing userdata') + await qdl.current.erase("userdata") + setProgress(0.9) - // TODO: run() is for testing, will be deleted so that qdl.js is a module - async run() { - try { - let flashPartition = "boot"; - let erasePartition = "cache"; + setMessage('Rebooting') + await qdl.current.reset(); + setProgress(1) + setConnected(false) + } - await this.toCmdMode(); + eraseDevice() + .then(() => { + console.debug('[QDL] Erase complete') + setStep(Step.DONE) + plausible('completed') + }) + .catch((err) => { + console.error('[QDL] Erase error', err) + setError(Error.ERASE_FAILED) + }) + break + } + } + }, [imageWorker, step]) - //let blob = await loadFileFromLocal(); - //await this.flashBlob(flashPartition, blob); + useEffect(() => { + if (error !== Error.NONE) { + console.debug('[QDL] error', error) + plausible('error', { props: { error }}) + setProgress(-1) + setOnContinue(null) - //await this.erase(erasePartition) + setOnRetry(() => () => { + console.debug('[QDL] on retry') + window.location.reload() + }) + } + }, [error]) - let partitions = await this.getDevicePartitions(); - console.log("Partitions:", partitions); + return { + step, + message, + progress, + error, - await this.reset(); + connected, + serial, - return true; - } catch (error) { - console.error(error); - return false; - } + onContinue, + onRetry, } -} +} \ No newline at end of file diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js new file mode 100644 index 0000000..c18cc8a --- /dev/null +++ b/src/QDL/qdlDevice.js @@ -0,0 +1,243 @@ +import { usbClass } from "./usblib" +import { Sahara } from "./sahara" +import { Firehose } from "./firehose" +import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" + + +export class qdlDevice { + cdc; + sahara; + mode; + + constructor() { + this.mode = ""; + this.cdc = new usbClass(); + this.sahara = new Sahara(this.cdc); + this.firehose = new Firehose(this.cdc); + this._connectResolve = null; + this._connectReject = null; + } + + + async waitForConnect() { + return await new Promise((resolve, reject) => { + this._connectResolve = resolve; + this._connectReject = reject; + }); + } + + + async connectToSahara() { + while (!this.cdc.connected){ + await this.cdc?.connect(); + if (this.cdc.connected){ + console.log("Device detected"); + try { + let resp = await this.sahara?.connect(); + if (resp.hasOwnProperty("mode")){ + let mode = resp["mode"]; + this.mode = mode; + console.log("Mode detected:", mode); + return resp; + } + } catch (error) { + console.error(error); + } + } + } + return {"mode" : "error"}; + } + + + async flashBlob(partitionName, blob, onProgress) { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to flash") + return false; + } + let startSector = 0; + let dp = await this.firehose?.detectPartition(partitionName); + if (dp[0]) { + let lun = dp[1]; + const imgSize = blob.byteLength; + let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); + if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) + imgSectors += 1; + if (partitionName.toLowerCase() !== "gpt") { + const partition = dp[2]; + if (imgSectors > partition.sectors) { + console.error("partition has fewer sectors compared to the flashing image"); + return false; + } + startSector = partition.sector; + console.log(`Flashing ${partitionName}...`); + if (await this.firehose.cmdProgram(lun, startSector, blob, onProgress)) { + console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); + } else { + console.error("Error writing image"); + } + } + } + return true; + } + + + async erase(partitionName) { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to erase") + return false; + } + let luns = this.firehose.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + if (guidGpt === null) + break; + if (guidGpt.partentries.hasOwnProperty(partitionName)) { + const partition = guidGpt.partentries[partitionName]; + console.log(`Erasing ${partitionName}...`) + await this.firehose.cmdErase(lun, partition.sector, partition.sectors); + console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sectors ${partition.sectors}`) + } else { + console.log(`Couldn't erase partition ${partitionName}. Either wrong type or not in lun ${lun}`); + continue; + } + } + return true; + } + + + async getDevicePartitions() { + const partitions = []; + const luns = this.firehose?.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + try { + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + + if (guidGpt === null) + return []; + for (const partitionName in guidGpt.partentries) { + let partition = partitionName; + if (partitionName.endsWith("_a") || partitionName.endsWith("_b")) + partition = partitionName.substring(0, partitionName.length-2); + if (partitions.includes(partition)) + continue; + partitions.push(partition); + } + } + return partitions; + } catch (error) { + console.error(error); + return []; + } + } + + + async getActiveSlot() { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to get active slot") + return false; + } + + const luns = this.firehose?.getLuns(); + let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; + for (const lun of luns) { + let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + if (guidGpt === null) + return "" + for (const partitionName in guidGpt.partentries) { + const slot = partitionName.slice(-2); + const partition = guidGpt.partentries[partitionName]; + const active = (((partition.flags >> (AB_FLAG_OFFSET*8))&0xff) & AB_PARTITION_ATTR_SLOT_ACTIVE) == AB_PARTITION_ATTR_SLOT_ACTIVE; + if (slot == "_a" && active) { + return "a"; + } else if (slot == "_b" && active) { + return "b"; + } + } + } + console.error("Can't detect slot A or B"); + return ""; + } + + + async setActvieSlot(slot) { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to set active slot"); + return false; + } + try { + await this.firehose.cmdSetActiveSlot(slot); + return true; + } catch (error) { + console.error(`Error while setting active slot: ${error}`) + return false; + } + } + + + async connect() { + try { + let resp = await this.connectToSahara(); + let mode = resp["mode"]; + if (mode === "sahara") + await this.sahara?.uploadLoader(2); // version 2 + await this.firehose?.configure(); + this.mode = "firehose"; + } catch (error) { + if (this._connectReject !== null) { + this._connectReject(error); + this._connectResolve = null; + this._connectReject = null; + } + } + + if (this._connectResolve !== null) { + this._connectResolve(undefined); + this._connectResolve = null; + this._connectReject = null; + } + + return true; + } + + + async reset() { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode reset") + return false; + } + try { + await this.firehose?.cmdReset(); + } catch (error) { + console.error(error); + } + return true; + } + + + // TODO: run() is for testing, will be deleted so that qdl.js is a module + async run() { + try { + let flashPartition = "boot"; + let erasePartition = "cache"; + + await this.connect(); + + //let blob = await loadFileFromLocal(); + //await this.flashBlob(flashPartition, blob); + + //await this.erase(erasePartition) + + let partitions = await this.getDevicePartitions(); + console.log("Partitions:", partitions); + + await this.reset(); + + return true; + } catch (error) { + console.error(error); + return false; + } + } +} diff --git a/src/QDL/sprase.js b/src/QDL/sparse.js similarity index 100% rename from src/QDL/sprase.js rename to src/QDL/sparse.js diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index fbdf1f3..f3b0316 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -11,7 +11,6 @@ export class UsbError extends Error { } } -// TODO: waitforconnect to check for valid device export class usbClass { device; epIn; @@ -20,6 +19,7 @@ export class usbClass { _registeredUsbListeners; constructor() { + this._ this.device = null; this.epIn = null; this.epOut = null; @@ -27,6 +27,7 @@ export class usbClass { this.maxSize = 512; } + get connected() { return ( this.device !== null && @@ -35,6 +36,7 @@ export class usbClass { ); } + async _validateAndConnectDevice() { let ife = this.device?.configurations[0].interfaces[0].alternates[0]; if (ife.endpoints.length !== 2) { @@ -70,10 +72,11 @@ export class usbClass { await this.device?.selectConfiguration(1); await this.device?.claimInterface(this.device.configuration.interfaces[0].interfaceNumber); } catch (error) { - throw error; + throw error; } } + async connect() { console.log("Trying to connect Qualcomm device") let devices = await navigator.usb.getDevices(); @@ -91,6 +94,7 @@ export class usbClass { console.log("USing USB device:", this.device); if (!this._registeredUsbListeners){ + console.log("Get in unregistered"); navigator.usb.addEventListener("connect", async (event) =>{ console.log("USB device connect:", event.device); @@ -100,6 +104,7 @@ export class usbClass { await this._validateAndConnectDevice(); } catch (error) { console.log("Error while connecting to the device"); + throw error; } }); @@ -108,6 +113,7 @@ export class usbClass { await this._validateAndConnectDevice(); } + async read(resplen=null){ let respData = new Uint8Array(); let covered = 0; diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx index f0b115f..da1de93 100644 --- a/src/app/Flash.jsx +++ b/src/app/Flash.jsx @@ -2,7 +2,8 @@ import { useCallback } from 'react' import Image from 'next/image' -import { Step, Error, useFastboot } from '@/utils/fastboot' +//import { Step, Error, useFastboot } from '@/utils/fastboot' +import { Step, Error, useQdl } from '@/QDL/qdl' import bolt from '@/assets/bolt.svg' import cable from '@/assets/cable.svg' @@ -189,7 +190,7 @@ export default function Flash() { connected, serial, - } = useFastboot() + } = useQdl() const handleContinue = useCallback(() => { onContinue?.() From 6fa5db4f8e35c0b7606e1fd5c14c8519b78b5624 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 04:09:56 -0500 Subject: [PATCH 028/112] maxlun = 6 --- src/QDL/firehose.js | 2 +- src/QDL/sahara.js | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 89d37ef..fb5732c 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -31,7 +31,7 @@ class cfg { this.SECTOR_SIZE_IN_BYTES = 0; this.MemoryName = "UFS"; this.prod_name = "Unknown"; - this.maxlun = 99; + this.maxlun = 6; } } diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 0d6d3d8..8c5e81e 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -15,8 +15,7 @@ export class Sahara { this.pktSize = null; this.version = null; this.ch = new CommandHandler(); - // TODO: change to auto upload Loader - this.programmer = "0005f0e100000000_b155b8bf19297f47_fhprg_peek.bin"; + this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; this.id = null; this.mode = ""; } From 6c705ae5e952d44a0d60aa01ba7fc1879ec31825 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 05:01:38 -0500 Subject: [PATCH 029/112] refactor --- src/QDL/firehose.js | 6 ++-- src/QDL/qdlDevice.js | 78 ++++++++++++++++++++----------------------- src/QDL/sahara.js | 37 ++++++++++++++++++-- src/QDL/saharaDefs.js | 6 +++- src/QDL/sparse.js | 2 +- src/QDL/usblib.js | 1 - 6 files changed, 81 insertions(+), 49 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index fb5732c..ec59052 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -1,5 +1,5 @@ import { xmlParser } from "./xmlParser" -import { concatUint8Array, containsBytes, compareStringToBytes, sleep, loadFileFromLocal } from "./utils" +import { concatUint8Array, containsBytes, compareStringToBytes, sleep } from "./utils" import { gpt } from "./gpt" import { QCSparse } from "./sparse"; @@ -137,6 +137,7 @@ export class Firehose { } + // TODO: better auto detect maxlun getLuns() { let luns = []; for (let i=0; i < this.cfg.maxlun; i++) @@ -335,7 +336,7 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress) { + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}) { let sparse = new QCSparse(blob); blob = new Uint8Array(blob) let total = blob.length; @@ -375,7 +376,6 @@ export class Firehose { bytesToWrite -= wlen; onProgress(offset/total); - if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + this.cfg.SECTOR_SIZE_IN_BYTES; diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index c18cc8a..a0d9935 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -1,9 +1,27 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" +import { loadFileFromLocal } from "./utils" import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" +function isRecognizedDevice(partitions) { + const expectedPartitions = [ + "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", + "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", + "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", + "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", + "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", + "xbl_config" + ] + if (!partitions.every(partition => expectedPartitions.includes(partition))) { + console.error("not expected device"); + return false; + } + return true; +} + + export class qdlDevice { cdc; sahara; @@ -14,16 +32,6 @@ export class qdlDevice { this.cdc = new usbClass(); this.sahara = new Sahara(this.cdc); this.firehose = new Firehose(this.cdc); - this._connectResolve = null; - this._connectReject = null; - } - - - async waitForConnect() { - return await new Promise((resolve, reject) => { - this._connectResolve = resolve; - this._connectReject = reject; - }); } @@ -49,7 +57,7 @@ export class qdlDevice { } - async flashBlob(partitionName, blob, onProgress) { + async flashBlob(partitionName, blob) { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode to flash") return false; @@ -70,7 +78,7 @@ export class qdlDevice { } startSector = partition.sector; console.log(`Flashing ${partitionName}...`); - if (await this.firehose.cmdProgram(lun, startSector, blob, onProgress)) { + if (await this.firehose.cmdProgram(lun, startSector, blob)) { console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); } else { console.error("Error writing image"); @@ -176,28 +184,13 @@ export class qdlDevice { } - async connect() { - try { - let resp = await this.connectToSahara(); - let mode = resp["mode"]; - if (mode === "sahara") - await this.sahara?.uploadLoader(2); // version 2 - await this.firehose?.configure(); - this.mode = "firehose"; - } catch (error) { - if (this._connectReject !== null) { - this._connectReject(error); - this._connectResolve = null; - this._connectReject = null; - } - } - - if (this._connectResolve !== null) { - this._connectResolve(undefined); - this._connectResolve = null; - this._connectReject = null; - } - + async toCmdMode() { + let resp = await this.connectToSahara(); + let mode = resp["mode"]; + if (mode === "sahara") + await this.sahara?.uploadLoader(2); // version 2 + await this.firehose?.configure(); + this.mode = "firehose"; return true; } @@ -222,15 +215,18 @@ export class qdlDevice { let flashPartition = "boot"; let erasePartition = "cache"; - await this.connect(); + await this.toCmdMode(); - //let blob = await loadFileFromLocal(); - //await this.flashBlob(flashPartition, blob); + let partitions = await this.getDevicePartitions(); + console.log("isRecognizedDevice:",isRecognizedDevice(partitions)); - //await this.erase(erasePartition) + let slot = await this.getActiveSlot(); + console.log("activeSlot:", slot); - let partitions = await this.getDevicePartitions(); - console.log("Partitions:", partitions); + let blob = await loadFileFromLocal(); + await this.flashBlob(flashPartition, blob); + + await this.erase(erasePartition); await this.reset(); @@ -240,4 +236,4 @@ export class qdlDevice { return false; } } -} +} \ No newline at end of file diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 8c5e81e..8240266 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -1,4 +1,4 @@ -import { CommandHandler, cmd_t, sahara_mode_t, status_t } from "./saharaDefs" +import { CommandHandler, cmd_t, sahara_mode_t, status_t, exec_cmd_t } from "./saharaDefs" import { concatUint8Array, packGenerator, loadFileFromLocal } from "./utils"; export class Sahara { @@ -15,8 +15,10 @@ export class Sahara { this.pktSize = null; this.version = null; this.ch = new CommandHandler(); - this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; + // TODO: change to auto upload Loader + this.programmer = "0005f0e100000000_b155b8bf19297f47_fhprg_peek.bin"; this.id = null; + this.serial = ""; this.mode = ""; } @@ -105,6 +107,35 @@ export class Sahara { } + async cmdExec(mcmd) { + let dataToSend = packGenerator([cmd_t.SAHARA_EXECUTE_REQ, 0xC, mcmd]); + await this.cdc.write(dataToSend); + let res = await this.getResponse(); + if (res.hasOwnProperty("cmd")) { + let cmd = res["cmd"]; + if (cmd == cmd_t.SAHARA_EXECUTE_RSP) { + let pkt = res["data"]; + let data = packGenerator([cmd_t.SAHARA_EXECUTE_DATA, 0xC, mcmd]); + await this.cdc.write(data); + let payload = await this.cdc.read(pkt.data_len); + return payload; + } else if (cmd == cmd_t.SAHARA_END_TRANSFER) { + let pkt = res["data"]; + console.error("error while executing command"); + } + return null; + } + return res; + } + + + async cmdGetSerialNum() { + let res = await this.cmdExec(exec_cmd_t.SAHARA_EXEC_CMD_SERIAL_NUM_READ); + let data = new DataView(res.buffer, 0).getUint32(0, true); + return data.toString(16).padStart(8, '0'); + } + + async enterCommandMode(version=2) { if (!await this.cmdHello(sahara_mode_t.SAHARA_MODE_COMMAND)){ return false; @@ -130,9 +161,11 @@ export class Sahara { return "error" } else { try { + this.serial = await this.cmdGetSerialNum(); await this.cmdModeSwitch(sahara_mode_t.SAHARA_MODE_COMMAND); } catch (error) { console.error(error); + return; } } diff --git a/src/QDL/saharaDefs.js b/src/QDL/saharaDefs.js index 5e65eb8..279d388 100644 --- a/src/QDL/saharaDefs.js +++ b/src/QDL/saharaDefs.js @@ -16,6 +16,10 @@ export const cmd_t = { SAHARA_64BIT_MEMORY_READ_DATA : 0x12, } +export const exec_cmd_t = { + SAHARA_EXEC_CMD_SERIAL_NUM_READ : 0x01 +} + export const sahara_mode_t = { SAHARA_MODE_IMAGE_TX_PENDING : 0x0, SAHARA_MODE_COMMAND : 0x3 @@ -152,4 +156,4 @@ export class CommandHandler { data_len : st.dword(), } } -} +} \ No newline at end of file diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index b98c8f1..db00ae1 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -190,4 +190,4 @@ export class QCSparse { } } } -} +} \ No newline at end of file diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index f3b0316..4cf4e1d 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -19,7 +19,6 @@ export class usbClass { _registeredUsbListeners; constructor() { - this._ this.device = null; this.epIn = null; this.epOut = null; From 64ae7d4f104daf46105a5787cc427d021756e2c2 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 05:20:40 -0500 Subject: [PATCH 030/112] serial --- src/QDL/qdl.js | 2 +- src/QDL/qdlDevice.js | 78 +++++++++++++++++++++++--------------------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index ec2b691..e1f3733 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -168,7 +168,7 @@ export function useQdl() { return } - //setSerial(deviceInfo['serialno'] || 'unknown') + setSerial(qdl.current.sahara.serial || 'unknown') setConnected(true) plausible('device-connected') setStep(Step.DOWNLOADING) diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index a0d9935..c18cc8a 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -1,27 +1,9 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" -import { loadFileFromLocal } from "./utils" import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" -function isRecognizedDevice(partitions) { - const expectedPartitions = [ - "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", - "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", - "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", - "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", - "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", - "xbl_config" - ] - if (!partitions.every(partition => expectedPartitions.includes(partition))) { - console.error("not expected device"); - return false; - } - return true; -} - - export class qdlDevice { cdc; sahara; @@ -32,6 +14,16 @@ export class qdlDevice { this.cdc = new usbClass(); this.sahara = new Sahara(this.cdc); this.firehose = new Firehose(this.cdc); + this._connectResolve = null; + this._connectReject = null; + } + + + async waitForConnect() { + return await new Promise((resolve, reject) => { + this._connectResolve = resolve; + this._connectReject = reject; + }); } @@ -57,7 +49,7 @@ export class qdlDevice { } - async flashBlob(partitionName, blob) { + async flashBlob(partitionName, blob, onProgress) { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode to flash") return false; @@ -78,7 +70,7 @@ export class qdlDevice { } startSector = partition.sector; console.log(`Flashing ${partitionName}...`); - if (await this.firehose.cmdProgram(lun, startSector, blob)) { + if (await this.firehose.cmdProgram(lun, startSector, blob, onProgress)) { console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); } else { console.error("Error writing image"); @@ -184,13 +176,28 @@ export class qdlDevice { } - async toCmdMode() { - let resp = await this.connectToSahara(); - let mode = resp["mode"]; - if (mode === "sahara") - await this.sahara?.uploadLoader(2); // version 2 - await this.firehose?.configure(); - this.mode = "firehose"; + async connect() { + try { + let resp = await this.connectToSahara(); + let mode = resp["mode"]; + if (mode === "sahara") + await this.sahara?.uploadLoader(2); // version 2 + await this.firehose?.configure(); + this.mode = "firehose"; + } catch (error) { + if (this._connectReject !== null) { + this._connectReject(error); + this._connectResolve = null; + this._connectReject = null; + } + } + + if (this._connectResolve !== null) { + this._connectResolve(undefined); + this._connectResolve = null; + this._connectReject = null; + } + return true; } @@ -215,18 +222,15 @@ export class qdlDevice { let flashPartition = "boot"; let erasePartition = "cache"; - await this.toCmdMode(); + await this.connect(); - let partitions = await this.getDevicePartitions(); - console.log("isRecognizedDevice:",isRecognizedDevice(partitions)); - - let slot = await this.getActiveSlot(); - console.log("activeSlot:", slot); + //let blob = await loadFileFromLocal(); + //await this.flashBlob(flashPartition, blob); - let blob = await loadFileFromLocal(); - await this.flashBlob(flashPartition, blob); + //await this.erase(erasePartition) - await this.erase(erasePartition); + let partitions = await this.getDevicePartitions(); + console.log("Partitions:", partitions); await this.reset(); @@ -236,4 +240,4 @@ export class qdlDevice { return false; } } -} \ No newline at end of file +} From 2609cc99275db7817bebd2d6d46ba3a18cc46dba Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 23:33:48 -0500 Subject: [PATCH 031/112] trailing white space --- src/QDL/gpt.js | 4 +++- src/QDL/qdlDevice.js | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index f7df906..dc99af8 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -40,6 +40,7 @@ class structHelper { } } +// TODO: is this needed? snapdrag845 uses uefi const efiType = { 0x00000000 : "EFI_UNUSED", 0x024DEE41 : "EFI_MBR", @@ -128,6 +129,7 @@ const efiType = { 0x9198EFFC : "EFI_VMWARE_RESERVED", } + class gptHeader { constructor(data) { let sh = new structHelper(data); @@ -200,7 +202,7 @@ class partf { export class gpt { constructor(numPartEntries=0, partEntrySize=0, partEntryStartLba=0) { this.numPartEntries = numPartEntries; - this.partEntrySize = partEntrySize; + this.partEntrySize = partEntrySize; this.partEntryStartLba = partEntryStartLba; this.totalSectors = null; this.header = null; diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index c18cc8a..5a0f5a0 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -56,7 +56,8 @@ export class qdlDevice { } let startSector = 0; let dp = await this.firehose?.detectPartition(partitionName); - if (dp[0]) { + const found = dp[0]; + if (found) { let lun = dp[1]; const imgSize = blob.byteLength; let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); From 4e94310c147364ad08a30e02c2ee7ac8949ef0b4 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 28 Feb 2024 23:59:11 -0500 Subject: [PATCH 032/112] fix getactiveslot --- src/QDL/gpt.js | 26 ++++++++------------- src/QDL/qdlDevice.js | 53 +++++++++++++++++++++++++++++++------------ src/QDL/sahara.js | 3 +-- src/QDL/saharaDefs.js | 2 +- src/QDL/sparse.js | 2 +- 5 files changed, 51 insertions(+), 35 deletions(-) diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index dc99af8..49cd4ae 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -6,7 +6,6 @@ export const AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2); const AB_PARTITION_ATTR_UNBOOTABLE = (0x1 << 7); class structHelper { - pos = 0; constructor(data, pos = 0) { this.pos = pos; @@ -14,28 +13,24 @@ class structHelper { } qword(littleEndian=true) { - const view = new DataView(this.data.slice(this.pos, this.pos+8).buffer, 0); - this.pos += 8; + const view = new DataView(this.data.slice(this.pos, this.pos+=8).buffer, 0); return Number(view.getBigUint64(0, littleEndian)); } dword(littleEndian=true) { - let view = new DataView(this.data.slice(this.pos, this.pos+4).buffer, 0); - this.pos += 4; + let view = new DataView(this.data.slice(this.pos, this.pos+=4).buffer, 0); return view.getUint32(0, littleEndian); } bytes(rlen=1) { - const dat = this.data.slice(this.pos, this.pos+rlen); - this.pos += rlen; + const dat = this.data.slice(this.pos, this.pos+=rlen); if (rlen == 1) return dat[0]; return dat; } toString(rlen=1) { - const dat = this.data.slice(this.pos, this.pos+rlen); - this.pos += rlen; + const dat = this.data.slice(this.pos, this.pos+=rlen); return dat; } } @@ -129,7 +124,6 @@ const efiType = { 0x9198EFFC : "EFI_VMWARE_RESERVED", } - class gptHeader { constructor(data) { let sh = new structHelper(data); @@ -202,7 +196,7 @@ class partf { export class gpt { constructor(numPartEntries=0, partEntrySize=0, partEntryStartLba=0) { this.numPartEntries = numPartEntries; - this.partEntrySize = partEntrySize; + this.partEntrySize = partEntrySize; this.partEntryStartLba = partEntryStartLba; this.totalSectors = null; this.header = null; @@ -295,9 +289,9 @@ export class gpt { const partentry = new gptPartition(sdata); let flags = partentry.flags; if (active) { - flags |= AB_PARTITION_ATTR_SLOT_ACTIVE << (AB_FLAG_OFFSET*8); + flags |= Number(BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE) << (BigInt(AB_FLAG_OFFSET) * BigInt(8))); } else { - flags |= AB_PARTITION_ATTR_UNBOOTABLE << (AB_FLAG_OFFSET*9) + flags |= Number(BigInt(AB_PARTITION_ATTR_UNBOOTABLE) << (BigInt(AB_FLAG_OFFSET) * BigInt(8))); } partentry.flags = flags; let pdata = partentry.create(); @@ -318,9 +312,9 @@ export class gpt { const headeroffset = this.header.current_lba * this.sectorSize; let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); - headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(partdata)), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(new Array(4).fill(0)), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(headerdata)), true))); + headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(partdata).buffer), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(new Array(4).fill(0).buffer), true))); + headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(headerdata).buffer), true))); data.splice(headeroffset, this.header.header_size, headerdata); return data; } diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 5a0f5a0..b31b4ed 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -1,6 +1,7 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" +import { loadFileFromLocal } from "./utils" import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" @@ -54,6 +55,7 @@ export class qdlDevice { console.error("Please try again, must be in command mode to flash") return false; } + let startSector = 0; let dp = await this.firehose?.detectPartition(partitionName); const found = dp[0]; @@ -75,8 +77,12 @@ export class qdlDevice { console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); } else { console.error("Error writing image"); + return false; } } + } else { + console.error(`Can't find partition ${partitionName}`); + return false; } return true; } @@ -87,6 +93,7 @@ export class qdlDevice { console.error("Please try again, must be in command mode to erase") return false; } + let luns = this.firehose.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; for (const lun of luns) { @@ -108,8 +115,13 @@ export class qdlDevice { async getDevicePartitions() { - const partitions = []; - const luns = this.firehose?.getLuns(); + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to get device partitions info"); + return false; + } + + const partitions = []; + const luns = this.firehose?.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; try { for (const lun of luns) { @@ -117,10 +129,9 @@ export class qdlDevice { if (guidGpt === null) return []; - for (const partitionName in guidGpt.partentries) { - let partition = partitionName; - if (partitionName.endsWith("_a") || partitionName.endsWith("_b")) - partition = partitionName.substring(0, partitionName.length-2); + for (let partition in guidGpt.partentries) { + if (partition.endsWith("_a") || partition.endsWith("_b")) + partition = partition.substring(0, partition.length-2); if (partitions.includes(partition)) continue; partitions.push(partition); @@ -145,11 +156,11 @@ export class qdlDevice { for (const lun of luns) { let [ data, guidGpt ] = await this.firehose.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); if (guidGpt === null) - return "" + return ""; for (const partitionName in guidGpt.partentries) { const slot = partitionName.slice(-2); const partition = guidGpt.partentries[partitionName]; - const active = (((partition.flags >> (AB_FLAG_OFFSET*8))&0xff) & AB_PARTITION_ATTR_SLOT_ACTIVE) == AB_PARTITION_ATTR_SLOT_ACTIVE; + const active = (((BigInt(partition.flags) >> (BigInt(AB_FLAG_OFFSET) * BigInt(8))) & BigInt(0xFF)) & BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE)) === BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE); if (slot == "_a" && active) { return "a"; } else if (slot == "_b" && active) { @@ -167,6 +178,7 @@ export class qdlDevice { console.error("Please try again, must be in command mode to set active slot"); return false; } + try { await this.firehose.cmdSetActiveSlot(slot); return true; @@ -177,6 +189,17 @@ export class qdlDevice { } + async toCmdMode() { + let resp = await this.connectToSahara(); + let mode = resp["mode"]; + if (mode === "sahara") + await this.sahara?.uploadLoader(2); // version 2 + await this.firehose?.configure(); + this.mode = "firehose"; + return true; + } + + async connect() { try { let resp = await this.connectToSahara(); @@ -202,12 +225,12 @@ export class qdlDevice { return true; } - async reset() { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode reset") return false; } + try { await this.firehose?.cmdReset(); } catch (error) { @@ -223,15 +246,15 @@ export class qdlDevice { let flashPartition = "boot"; let erasePartition = "cache"; - await this.connect(); + await this.toCmdMode(); - //let blob = await loadFileFromLocal(); - //await this.flashBlob(flashPartition, blob); + let slot = await this.getActiveSlot(); + console.log("activeSlot:", slot); - //await this.erase(erasePartition) + let blob = await loadFileFromLocal(); + await this.flashBlob(flashPartition, blob); - let partitions = await this.getDevicePartitions(); - console.log("Partitions:", partitions); + await this.erase(erasePartition); await this.reset(); diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 8240266..8da2317 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -16,7 +16,7 @@ export class Sahara { this.version = null; this.ch = new CommandHandler(); // TODO: change to auto upload Loader - this.programmer = "0005f0e100000000_b155b8bf19297f47_fhprg_peek.bin"; + this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; this.id = null; this.serial = ""; this.mode = ""; @@ -154,7 +154,6 @@ export class Sahara { } - async uploadLoader(version){ if (!(await this.enterCommandMode(version))) { console.error("Failed to enter command mode in Sahara"); diff --git a/src/QDL/saharaDefs.js b/src/QDL/saharaDefs.js index 279d388..567edc6 100644 --- a/src/QDL/saharaDefs.js +++ b/src/QDL/saharaDefs.js @@ -156,4 +156,4 @@ export class CommandHandler { data_len : st.dword(), } } -} \ No newline at end of file +} diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index db00ae1..b98c8f1 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -190,4 +190,4 @@ export class QCSparse { } } } -} \ No newline at end of file +} From 18ca75102e33e86b3be89e89f1881d302ca57e70 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 29 Feb 2024 23:20:28 -0500 Subject: [PATCH 033/112] auto download loader --- src/QDL/qdl.js | 17 ++++++++++----- src/QDL/qdlDevice.js | 16 +++++++++----- src/QDL/sahara.js | 52 +++++++++++++++++++++++++++++++++++++++----- src/QDL/utils.js | 6 ++++- src/config.js | 3 +++ 5 files changed, 75 insertions(+), 19 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index e1f3733..c675c4c 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -39,7 +39,13 @@ export const Error = { REQUIREMENTS_NOT_MET: 8, } -function isRecognizedDevice(partitions) { +function isRecognizedDevice(maxDownloadSize, slotCount, partitions) { + + if (maxDownloadSize !== 104857600 || slotCount !== 2) { + console.error('[QDL] Unrecognised device (kernel, maxDownloadSize or slotCount)') + return false + } + // check we have the expected partitions to make sure it's a comma three const expectedPartitions = [ "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", @@ -53,7 +59,7 @@ function isRecognizedDevice(partitions) { console.error('[QDL] Unrecognised device (partitions)', partitions) return false } - return true; + return true } @@ -158,9 +164,9 @@ export function useQdl() { .then(() => { console.info('[QDL] Connected') return qdl.current.getDevicePartitions() - .then((partitions) => { - - const recognized = isRecognizedDevice(partitions) + .then(([slotCount, partitions]) => { + const maxDownloadSize = qdl.current.firehose.cfg.MaxPayloadSizeToTargetInBytes; + const recognized = isRecognizedDevice(maxDownloadSize, slotCount, partitions) console.debug('[QDL] Device info', { recognized, partitions}) if (!recognized) { @@ -183,7 +189,6 @@ export function useQdl() { setError(Error.LOST_CONNECTION) setConnected(false) }) - qdl.current.connect() .catch((err) => { console.error('[QDL] Connection error', err) diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index b31b4ed..e2d6556 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -120,6 +120,7 @@ export class qdlDevice { return false; } + const slots = []; const partitions = []; const luns = this.firehose?.getLuns(); let gptNumPartEntries = 0, gptPartEntrySize = 0, gptPartEntryStartLba = 0; @@ -130,17 +131,20 @@ export class qdlDevice { if (guidGpt === null) return []; for (let partition in guidGpt.partentries) { - if (partition.endsWith("_a") || partition.endsWith("_b")) + let slot = partition.slice(-2); + if (slot === "_a" || slot === "_b") { partition = partition.substring(0, partition.length-2); - if (partitions.includes(partition)) - continue; - partitions.push(partition); + if (!slots.includes(slot)) + slots.push(slot); + } + if (!partitions.includes(partition)) + partitions.push(partition); } } - return partitions; + return [slots.length, partitions]; } catch (error) { console.error(error); - return []; + return [null, null]; } } diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 8da2317..6dbd52a 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -1,5 +1,6 @@ import { CommandHandler, cmd_t, sahara_mode_t, status_t, exec_cmd_t } from "./saharaDefs" -import { concatUint8Array, packGenerator, loadFileFromLocal } from "./utils"; +import { concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; +import config from '@/config' export class Sahara { cdc; @@ -25,7 +26,6 @@ export class Sahara { async connect() { try { let v = await this.cdc?.read(0xC * 0x4); - let v_text = new TextDecoder("utf-8").decode(v); if (v.length > 1){ if (v[0] == 0x01){ let pkt = this.ch.pkt_cmd_hdr(v); @@ -154,6 +154,44 @@ export class Sahara { } + async downLoadLoader() { + let writable; + try { + const fileHandle = await root.getFileHandle(this.programmer, { create: true }); + writable = await fileHandle.createWritable(); + } catch (e) { + throw `Error opening file handle: ${e}`; + } + + const programmerUrl = config.loader['url']; + const response = await fetch(programmerUrl, { mode: 'cors' }) + if (!response.ok) { + throw `Fetch failed: ${response.status} ${response.statusText}` + } + + try { + let processed = 0; + const contentLength = +response.headers.get('Content-Length'); + const reader = response.body.getReader(); + while (true) { + const { done, value } = await reader.read(); + if (done) + break; + await writable.write(value); + processed += value.length; + } + } catch (e) { + throw `Could not read response body: ${e}` + } + + try { + await writable.close() + } catch (e) { + throw `Error closing file handle: ${e}` + } + } + + async uploadLoader(version){ if (!(await this.enterCommandMode(version))) { console.error("Failed to enter command mode in Sahara"); @@ -174,9 +212,11 @@ export class Sahara { } console.log("Uploading Programmer..."); - let programmer = new Uint8Array(await loadFileFromLocal()); + // TODO: change to auto download + //let programmer = new Uint8Array(await readBlobAsBuffer(await downloadLoader())); + let programmer = new Uint8Array(await readBlobAsBuffer(await loadFileFromLocal())); if (!(await this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version))) { - return ""; + return "error"; } try { @@ -190,11 +230,11 @@ export class Sahara { cmd = resp["cmd"]; } else { console.error("Timeout while uploading loader. Wrong loader?"); - return "" + return "error" } if (cmd == cmd_t.SAHARA_DONE_REQ){ if (self.cmdDone()){ - return "" + return "error" } } if ([cmd_t.SAHARA_64BIT_MEMORY_READ_DATA,cmd_t.SAHARA_READ_DATA].includes(cmd)) { diff --git a/src/QDL/utils.js b/src/QDL/utils.js index a8dd517..12a31aa 100644 --- a/src/QDL/utils.js +++ b/src/QDL/utils.js @@ -61,7 +61,11 @@ export function compareStringToBytes(compareString, array) { export async function loadFileFromLocal() { const [fileHandle] = await window.showOpenFilePicker(); - const blob = await fileHandle.getFile(); + let blob = await fileHandle.getFile(); + return blob; +} + +export function readBlobAsBuffer(blob) { return new Promise((resolve, reject) => { let reader = new FileReader(); reader.onload = () => { diff --git a/src/config.js b/src/config.js index 7d5ef34..3f767ee 100644 --- a/src/config.js +++ b/src/config.js @@ -3,6 +3,9 @@ const config = { // release3: 'https://raw.githubusercontent.com/commaai/openpilot/release3/system/hardware/tici/agnos.json', master: 'https://raw.githubusercontent.com/commaai/openpilot/master/system/hardware/tici/agnos.json', }, + edlLoader : { + url: "", + }, } export default config From 947374a8921f15b2089d18b8e79a50a413a1eb25 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 13 Mar 2024 05:06:27 -0400 Subject: [PATCH 034/112] setactiveslot --- src/QDL/firehose.js | 330 ++++++++++++++++++++++++++++------------ src/QDL/gpt.js | 70 ++++----- src/QDL/qdlDevice.js | 43 +++++- src/QDL/sahara.js | 7 +- src/QDL/sparse.js | 353 ++++++++++++++++++++++++++++++++----------- src/QDL/usblib.js | 2 +- src/QDL/utils.js | 9 ++ 7 files changed, 584 insertions(+), 230 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index ec59052..f9c14c1 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -1,7 +1,7 @@ import { xmlParser } from "./xmlParser" -import { concatUint8Array, containsBytes, compareStringToBytes, sleep } from "./utils" -import { gpt } from "./gpt" -import { QCSparse } from "./sparse"; +import { concatUint8Array, containsBytes, compareStringToBytes, sleep, fromUint8ArrayToNumber, readBlobAsBuffer } from "./utils" +import * as gpt from "./gpt" +import * as Sparse from "./sparse"; class response { @@ -22,13 +22,14 @@ class cfg { this.SkipStorageInit = 0; this.SkipWrite = 0; this.MaxPayloadSizeToTargetInBytes = 1048576; - this.MaxPayloadSizeFromTargetInBytes = 8192; + //this.MaxPayloadSizeToTargetInBytes = 32768; + this.MaxPayloadSizeFromTargetInBytes = 4096; this.MaxXMLSizeInBytes = 4096; this.bit64 = true; this.total_blocks = 0; this.num_physical = 0; this.block_size = 0; - this.SECTOR_SIZE_IN_BYTES = 0; + this.SECTOR_SIZE_IN_BYTES = 4096; // ufs sector size is 4096 this.MemoryName = "UFS"; this.prod_name = "Unknown"; this.maxlun = 6; @@ -109,10 +110,7 @@ export class Firehose { } - async configure() { - if (this.cfg.SECTOR_SIZE_IN_BYTES == 0) - this.cfg.SECTOR_SIZE_IN_BYTES = 4096 - + async configure(lvl) { let connectCmd = `` + `` let rsp = await this.xmlSend(connectCmd, false); - if (rsp === null || !rsp.resp) { + if (rsp === null || !rsp.resp | rsp === undefined ) { if (rsp.error == "") { - return await this.configure(); + return await this.configure(lvl+1); } } else { + // TODO: delete if not needed + if (typeof rsp.resp === "object") { + let field = rsp.resp; + if (field.hasOwnProperty("MaxPayloadSizeToTargetInBytes")) { + this.cfg.MaxPayloadSizeToTargetInBytes = parseInt(field["MaxPayloadSizeToTargetInBytes"]); + } + if (field.hasOwnProperty("MaxXMLSizeInBytes")) { + this.cfg.MaxXMLSizeInBytes = parseInt(field["MaxXMLSizeInBytes"]); + } + if (field.hasOwnProperty("MaxPayloadSizeFromTargetInBytes")) { + this.cfg.MaxPayloadSizeFromTargetInBytes = parseInt(field["MaxPayloadSizeFromTargetInBytes"]); + } + if (lvl == 0) { + return this.configure(lvl + 1); + } + } await this.parseStorage(); this.luns = this.getLuns(); return true; @@ -205,7 +219,7 @@ export class Firehose { } - async detectPartition(partitionName) { + async detectPartition(partitionName, sendFull=false) { let fPartitions = {}; for (const lun of this.luns) { @@ -215,12 +229,13 @@ export class Firehose { const gptPartEntrySize = 0; const gptPartEntryStartLba = 0; - let [ data, guidGpt ] = await this.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + const [ data, guidGpt ] = await this.getGpt(lun, gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); if (guidGpt === null) { break; } else { if (guidGpt.partentries.hasOwnProperty(partitionName)) { - return [true, lun, guidGpt.partentries[partitionName]] + + return sendFull ? [true, lun, data, guidGpt] : [true, lun, guidGpt.partentries[partitionName]]; } } for (const part in guidGpt.partentries) @@ -243,27 +258,23 @@ export class Firehose { } let data = resp.data; - let guidGpt = new gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); + let guidGpt = new gpt.gpt(gptNumPartEntries, gptPartEntrySize, gptPartEntryStartLba); try { const header = guidGpt.parseHeader(data, this.cfg.SECTOR_SIZE_IN_BYTES); if (containsBytes("EFI PART", header.signature)) { const gptSize = (header.part_entry_start_lba * this.cfg.SECTOR_SIZE_IN_BYTES) + - (header.num_part_entries * header.part_entry_size); + header.num_part_entries * header.part_entry_size; let sectors = Math.floor(gptSize / this.cfg.SECTOR_SIZE_IN_BYTES); - if (gptSize % this.cfg.SECTOR_SIZE_IN_BYTES != 0) sectors += 1; - if (sectors === 0) + if (sectors == 0) sectors = 64; if (sectors > 64) sectors = 64; - data = await this.cmdReadBuffer(lun, 0, sectors); - if (compareStringToBytes("", data.data)) return [null, null]; - guidGpt.parse(data.data, this.cfg.SECTOR_SIZE_IN_BYTES); return [data.data, guidGpt]; } else { @@ -336,116 +347,234 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}) { - let sparse = new QCSparse(blob); - blob = new Uint8Array(blob) - let total = blob.length; - let sparseformat = false + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}, test=true) { + let total = blob.size; + let sparseformat = false; - if (sparse.parseFileHeader()) { + let sparseHeader = await Sparse.parseFileHeader(blob.slice(0, Sparse.FILE_HEADER_SIZE)); + let sparseImage; + if (sparseHeader !== null) { + sparseImage = new Sparse.QCSparse(blob, sparseHeader) sparseformat = true; - total = sparse.getSize(); + total = await sparseImage.getSize(); + console.log("size of image:", total); } - let bytesToWrite = total; let numPartitionSectors = Math.floor(total/this.cfg.SECTOR_SIZE_IN_BYTES); - - if (total % this.cfg.SECTOR_SIZE_IN_BYTES !== 0) + if (total % this.cfg.SECTOR_SIZE_IN_BYTES != 0) numPartitionSectors += 1; - const data = `\n` + + const data = `\n` + `\n`; - let rsp = await this.xmlSend(data); - let offset = 0; - if (rsp.resp) { - while (bytesToWrite > 0) { - let wlen = Math.min(bytesToWrite, this.cfg.MaxPayloadSizeFromTargetInBytes); - let wdata; - - if (sparseformat) { - wdata = sparse.read(wlen); - } else { - wdata = blob.slice(offset, offset + wlen); - } - offset += wlen; - bytesToWrite -= wlen; - onProgress(offset/total); - - if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ - let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + - this.cfg.SECTOR_SIZE_IN_BYTES; - const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); - wdata = concatUint8Array([wdata, fillArray]); - } + let bytesWritten = 0; - await this.cdc.write(wdata); - console.log(`Progress: ${Math.floor(offset/total)*100}%`); - await this.cdc.write(new Uint8Array(0), null, true, true); + for await (let split of Sparse.splitBlob(blob)) { + let offset = 0; + let bytesToWriteSplit = split.size; + let sparseSplit; + + if (sparseformat) { + let sparseSplitHeader = await Sparse.parseFileHeader(split.slice(0, Sparse.FILE_HEADER_SIZE)); + sparseSplit = new Sparse.QCSparse(split, sparseSplitHeader); + bytesToWriteSplit = await sparseSplit.getSize(); } - const wd = await this.waitForData(); - const log = this.xml.getLog(wd); - const rsp = this.xml.getReponse(wd); - if (rsp.hasOwnProperty("value")) { - if (rsp["value"] !== "ACK") { - console.error("ERROR") - return false; + if (rsp.resp) { + while (bytesToWriteSplit > 0) { + let wlen = Math.min(bytesToWriteSplit, this.cfg.MaxPayloadSizeToTargetInBytes); + let wdata; + + if (sparseformat) { + wdata = await sparseSplit?.read(wlen); + } else { + wdata = new Uint8Array(await readBlobAsBuffer(split.slice(offset, offset + wlen))); + } + + offset += wlen; + bytesToWriteSplit -= wlen; + bytesWritten += wlen; + onProgress(bytesWritten/total); + + //console.log("progress:", total - bytesWritten); + + if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ + let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + + this.cfg.SECTOR_SIZE_IN_BYTES; + const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); + wdata = concatUint8Array([wdata, fillArray]); + } + await this.cdc.write(wdata); + //console.log(`Progress: ${Math.floor(offset/total)*100}%`); + await this.cdc.write(new Uint8Array(0), null, true, true); } - } else { - console.error("Error:", rsp); + } + } + console.log("waiting"); + const wd = await this.waitForData(); + console.log("finish waiting") + const log = this.xml.getLog(wd); + const resposne = this.xml.getReponse(wd); + if (resposne.hasOwnProperty("value")) { + if (resposne["value"] !== "ACK") { + console.error("ERROR") return false; } + } else { + console.error("Error:", resposne); + return false; + } + return true; + } + + async cmdPatchMultiple(lun, startSector, byteOffset, patchData) { + const writeSize = patchData.length; + const sizeEachPatch = 4; + let offset = 0; + for (let i = 0; i < writeSize; i += sizeEachPatch) { + const pdataSubset = fromUint8ArrayToNumber(patchData.slice(offset, offset+sizeEachPatch)); + await this.cmdPatch(lun, startSector, byteOffset+offset, pdataSubset, sizeEachPatch); + offset += sizeEachPatch; } return true; } + setPartitionFlags(flags, active, isBoot) { + let newFlags = BigInt(flags); + if (active) { + if (isBoot) { + //newFlags |= (gpt.PART_ATT_PRIORITY_VAL | gpt.PART_ATT_ACTIVE_VAL | gpt.PART_ATT_MAX_RETRY_COUNT_VAL); + //newFlags &= (~gpt.PART_ATT_SUCCESSFUL_VAL & ~gpt.PART_ATT_UNBOOTABLE_VAL); + newFlags = BigInt(0x006f) << gpt.PART_ATT_PRIORITY_BIT; + } else { + newFlags |= gpt.PART_ATT_ACTIVE_VAL; + } + } else { + if (isBoot) { + //newFlags &= (~gpt.PART_ATT_PRIORITY_VAL & ~gpt.PART_ATT_ACTIVE_VAL); + //newFlags |= ((gpt.MAX_PRIORITY-BigInt(1)) << gpt.PART_ATT_PRIORITY_BIT); + newFlags = BigInt(0x003a) << gpt.PART_ATT_PRIORITY_BIT; + } else { + newFlags &= ~gpt.PART_ATT_ACTIVE_VAL; + } + } + return Number(newFlags); + } + + patchSetActiveHelper(headerA, headerB, guidGpt, partA, partB, slot_a_status, slot_b_status, isBoot) { + const partEntrySize = guidGpt.header.part_entry_size; + + const sdataA = headerA.slice(partA.entryOffset, partA.entryOffset+partEntrySize); + const sdataB = headerB.slice(partB.entryOffset, partB.entryOffset+partEntrySize); + + const partEntryA = new gpt.gptPartition(sdataA); + const partEntryB = new gpt.gptPartition(sdataB); + + partEntryA.flags = this.setPartitionFlags(partEntryA.flags, slot_a_status, isBoot); + partEntryB.flags = this.setPartitionFlags(partEntryB.flags, slot_b_status, isBoot); + const tmp = partEntryB.type; + partEntryB.type = partEntryA.type; + partEntryA.type = tmp; + const pDataA = partEntryA.create(), pDataB = partEntryB.create(); + + return [pDataA, partA.entryOffset, pDataB, partB.entryOffset]; + } + async cmdSetActiveSlot(slot) { slot = slot.toLowerCase(); const luns = this.getLuns(); - let partSlots = {}; + let slot_a_status, slot_b_status; if (slot == "a") { - partSlots["_a"] = true; - partSlots["_b"] = false; + slot_a_status = true; } else if (slot == "b") { - partSlots["_a"] = false; - partSlots["_b"] = true; + slot_a_status = false; } else { console.error("Only slots a or b are accepted. Aborting."); return false; } + slot_b_status = !slot_a_status; - for (const lun of luns) { - const [ data, guidGpt ] = await this.getGpt(lun, 0, 0, 0); - if (guidGpt === null) - break; - for (const partitionName in guidGpt.partentries) { - const gp = new gpt(); - slot = partitionName.toLowerCase().slice(-2); - if (slot === "a" || slot === "b") { - const [ pdata, pOffset ] = gp.patch(data, partitionName, partSlots[slot]); - data.splice(pOffset, pdata.length, pdata); - let wdata = gp.fixGptCrc(data); - - if (wdata !== null) { - const startSectorPath = Math.floor(pOffset/this.cfg.SECTOR_SIZE_IN_BYTES); - const byteOffsetPatch = pOffset % this.cfg.SECTOR_SIZE_IN_BYTES; - const headerOffset = gp.header.current_lba * gp.sectorSize; - const startSectorHdr = Math.floor(headerOffset/this.cfg.SECTOR_SIZE_IN_BYTES); - const header = wdata.slice(startSectorHdr, startSectorHdr+gp.header.header_size); - - await this.cmdPatch(lun, startSectorPath, byteOffsetPatch, pdata, pdata.length); - await this.cmdPatch(lun, headerOffset, 0, header, pdata.length); + try { + for (const lunA of luns) { + let [ headerA, guidGptA ] = await this.getGpt(lunA, 0, 0, 0); + if (guidGptA === null) + break; + for (const partitionNameA in guidGptA.partentries) { + let slotSuffix = partitionNameA.toLowerCase().slice(-2); + if (slotSuffix === "_a") { + const partitionNameB = partitionNameA.slice(0, partitionNameA.length-1) + "b"; + let sts, lunB, headerB, guidGptB; + if (guidGptA.partentries.hasOwnProperty(partitionNameB)) { + lunB = lunA; + headerB = headerA; + guidGptB = guidGptA; + } else { + const resp = await this.detectPartition(partitionNameB, true); + sts = resp[0]; + if (!sts) { + console.error(`Cannot find partition ${partitionNameB}`); + return false; + } + [sts, lunB, headerB, guidGptB] = resp; + } + + const partA = guidGptA.partentries[partitionNameA]; + const partB = guidGptB.partentries[partitionNameB]; + + let isBoot = false; + if (partitionNameA === "boot_a") + isBoot = true; + const [pDataA, pOffsetA, pDataB, pOffsetB] = this.patchSetActiveHelper( + headerA, headerB, guidGptA, partA, partB, slot_a_status, slot_b_status, isBoot + ); + + headerA.set(pDataA, pOffsetA); + const newHeaderA = guidGptA.fixGptCrc(headerA); + if (lunA === lunB) + headerB = newHeaderA; + headerB.set(pDataB, pOffsetB); + const newHeaderB = guidGptB.fixGptCrc(headerB); + + if (headerA !== null) { + const startSectorPatchA = Math.floor(pOffsetA / this.cfg.SECTOR_SIZE_IN_BYTES); + const byteOffsetPatchA = pOffsetA % this.cfg.SECTOR_SIZE_IN_BYTES; + await this.cmdPatchMultiple(lunA, startSectorPatchA, byteOffsetPatchA, pDataA); + + + if (lunA !== lunB) { + const headerOffsetA = guidGptA.header.current_lba * guidGptA.sectorSize; + const startSectorHdrA = guidGptA.header.current_lba; + const pHeaderA = newHeaderA.slice(headerOffsetA, headerOffsetA+guidGptA.header.header_size); + await this.cmdPatchMultiple(lunA, startSectorHdrA, 0, pHeaderA); + } + } + if (headerB !== null) { + const startSectorPatchB = Math.floor(pOffsetB /this.cfg.SECTOR_SIZE_IN_BYTES); + const byteOffsetPatchB = pOffsetB % this.cfg.SECTOR_SIZE_IN_BYTES; + await this.cmdPatchMultiple(lunB, startSectorPatchB, byteOffsetPatchB, pDataB); + + const headerOffsetB = guidGptB.header.current_lba * guidGptB.sectorSize; + const startSectorHdrB = guidGptB.header.current_lba; + const pHeaderB = newHeaderB.slice(headerOffsetB, headerOffsetB+guidGptB.header.header_size); + await this.cmdPatchMultiple(lunB, startSectorHdrB, 0, pHeaderB); + } } } } + } catch (error) { + console.error(`Failed setting slot ${slot} active`); + console.error(error); + return false } + let activeBootLunId = (slot === "a") ? 1 : 2; + await this.cmdSetBootLunId(activeBootLunId); + return true; } @@ -461,8 +590,9 @@ export class Firehose { let rsp = await this.xmlSend(data); if (rsp.resp) { - console.log("Patch:\n--------------------\n"); - console.log(rsp.data); + //console.log("Patch:\n--------------------\n"); + //console.log(rsp.data); + console.log(`Patched successfully`); return true; } else { console.error(`Error: ${rsp.error}`); @@ -470,6 +600,18 @@ export class Firehose { } } + async cmdSetBootLunId(lun) { + const data = `\n` + const val = await this.xmlSend(data); + if (val.resp) { + console.log(`Successfully set bootID to lun ${lun}`); + return true; + } else { + console.error(`Failed to set boot lun ${lun}`); + return false; + } + } + async cmdErase(physicalPartitionNumber, startSector, numPartitionSectors) { const data = `\n` + diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index 49cd4ae..3804918 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -1,10 +1,23 @@ const { containsBytes } = require("./utils"); -const CRC32 = require("crc-32"); +var CRC32 = require("crc-32"); export const AB_FLAG_OFFSET = 6; export const AB_PARTITION_ATTR_SLOT_ACTIVE = (0x1 << 2); const AB_PARTITION_ATTR_UNBOOTABLE = (0x1 << 7); +export const PART_ATT_PRIORITY_BIT = BigInt(48) +export const PART_ATT_ACTIVE_BIT = BigInt(50) +export const PART_ATT_MAX_RETRY_CNT_BIT = BigInt(51) +export const MAX_PRIORITY = BigInt(3) +export const PART_ATT_SUCCESS_BIT = BigInt(54) +export const PART_ATT_UNBOOTABLE_BIT = BigInt(55) + +export const PART_ATT_PRIORITY_VAL = BigInt(0x3) << PART_ATT_PRIORITY_BIT +export const PART_ATT_ACTIVE_VAL = BigInt(0x1) << PART_ATT_ACTIVE_BIT +export const PART_ATT_MAX_RETRY_COUNT_VAL = BigInt(0x7) << PART_ATT_MAX_RETRY_CNT_BIT +export const PART_ATT_SUCCESSFUL_VAL = BigInt(0x1) << PART_ATT_SUCCESS_BIT +export const PART_ATT_UNBOOTABLE_VAL = BigInt(0x1) << PART_ATT_UNBOOTABLE_BIT + class structHelper { constructor(data, pos = 0) { @@ -145,7 +158,7 @@ class gptHeader { } -class gptPartition { +export class gptPartition { constructor(data) { let sh = new structHelper(data) this.type = sh.bytes(16); @@ -162,14 +175,14 @@ class gptPartition { let view = new DataView(buffer); let offset = 0; for (let i = 0; i < this.type.length; i++) { - view.setUint8(offset++, this.type[i]); + view.setUint8(offset++, this.type[i], true); } for (let i = 0; i < this.unique.length; i++) { - view.setUint8(offset++, this.unique[i]); + view.setUint8(offset++, this.unique[i], true); } - let tmp = [this.first_lba, this.last_lba, this.flags]; + let tmp = [BigInt(this.first_lba), BigInt(this.last_lba), BigInt(this.flags)]; for (let i = 0; i < 3; i++) { - view.setBigInt64(offset, tmp[i]); + view.setBigUint64(offset, tmp[i], true); offset += 8; } for (let i = 0; i < 72; i++) { @@ -202,6 +215,7 @@ export class gpt { this.header = null; this.sectorSize = null; this.partentries = {}; + this.header = null; } parseHeader(gptData, sectorSize=512){ @@ -278,44 +292,22 @@ export class gpt { } - patch(data, partitionName="boot", active=true) { - for (const sectorSize of [512, 4096]) { - const result = this.parse(data, sectorSize); - if (result) { - for (const rname in this.partentries) { - if (partitionName.toLowerCase() === rname.toLowerCase()) { - const partition = this.partentries[rname]; - const sdata = data.slice(partition.entryOffset, partition.entryOffset+this.header.part_entry_size); - const partentry = new gptPartition(sdata); - let flags = partentry.flags; - if (active) { - flags |= Number(BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE) << (BigInt(AB_FLAG_OFFSET) * BigInt(8))); - } else { - flags |= Number(BigInt(AB_PARTITION_ATTR_UNBOOTABLE) << (BigInt(AB_FLAG_OFFSET) * BigInt(8))); - } - partentry.flags = flags; - let pdata = partentry.create(); - return [ pdata, partition.entryOffset ]; - } - } - break; - } - } - return [ null, null ]; - } - - fixGptCrc(data) { const partentry_size = this.header.num_part_entries * this.header.part_entry_size; const partentry_offset = this.header.part_entry_start_lba * this.sectorSize; - const partdata = data.slice(partentry_offset, partentry_offset + partentry_size); + const partdata = Uint8Array.from(data.slice(partentry_offset, partentry_offset + partentry_size)); const headeroffset = this.header.current_lba * this.sectorSize; - let headerdata = data.slice(headeroffset, headeroffset+this.header.header_size); + let headerdata = Uint8Array.from(data.slice(headeroffset, headeroffset+this.header.header_size)); + + let view = new DataView(new ArrayBuffer(4)) + view.setInt32(0, CRC32.buf(Buffer.from(partdata)), true) + headerdata.set(new Uint8Array(view.buffer), 0x58); + view.setInt32(0, 0, true); + headerdata.set(new Uint8Array(view.buffer) , 0x10); + view.setInt32(0, CRC32.buf(Buffer.from(headerdata)), true) + headerdata.set(new Uint8Array(view.buffer), 0x10); - headerdata.splice(0x58, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(partdata).buffer), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(new Array(4).fill(0).buffer), true))); - headerdata.splice(0x10, 4, new Uint8Array(new DataView(new ArrayBuffer(4)).setUint8(0, CRC32.buf(Array.from(headerdata).buffer), true))); - data.splice(headeroffset, this.header.header_size, headerdata); + data.set(headerdata, headeroffset) return data; } } diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index e2d6556..2eac2fd 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -4,6 +4,29 @@ import { Firehose } from "./firehose" import { loadFileFromLocal } from "./utils" import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" +function isRecognizedDevice(slotCount, partitions) { + + if (slotCount !== 2) { + console.error('[QDL] Unrecognised device (kernel, slotCount)') + return false + } + + // check we have the expected partitions to make sure it's a comma three + const expectedPartitions = [ + "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", + "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", + "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", + "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", + "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", + "xbl_config" + ] + if (!partitions.every(partition => expectedPartitions.includes(partition))) { + console.error('[QDL] Unrecognised device (partitions)', partitions) + return false + } + return true +} + export class qdlDevice { cdc; @@ -61,7 +84,7 @@ export class qdlDevice { const found = dp[0]; if (found) { let lun = dp[1]; - const imgSize = blob.byteLength; + const imgSize = blob.size; let imgSectors = Math.floor(imgSize/this.firehose.cfg.SECTOR_SIZE_IN_BYTES); if (imgSize % this.firehose.cfg.SECTOR_SIZE_IN_BYTES !== 0) imgSectors += 1; @@ -164,7 +187,8 @@ export class qdlDevice { for (const partitionName in guidGpt.partentries) { const slot = partitionName.slice(-2); const partition = guidGpt.partentries[partitionName]; - const active = (((BigInt(partition.flags) >> (BigInt(AB_FLAG_OFFSET) * BigInt(8))) & BigInt(0xFF)) & BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE)) === BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE); + const active = (((BigInt(partition.flags) >> (BigInt(AB_FLAG_OFFSET) * BigInt(8)))) + & BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE)) === BigInt(AB_PARTITION_ATTR_SLOT_ACTIVE); if (slot == "_a" && active) { return "a"; } else if (slot == "_b" && active) { @@ -196,8 +220,11 @@ export class qdlDevice { async toCmdMode() { let resp = await this.connectToSahara(); let mode = resp["mode"]; - if (mode === "sahara") + if (mode === "sahara") { await this.sahara?.uploadLoader(2); // version 2 + } else { + return false; + } await this.firehose?.configure(); this.mode = "firehose"; return true; @@ -247,7 +274,7 @@ export class qdlDevice { // TODO: run() is for testing, will be deleted so that qdl.js is a module async run() { try { - let flashPartition = "boot"; + let flashPartition = "system_a"; let erasePartition = "cache"; await this.toCmdMode(); @@ -255,11 +282,17 @@ export class qdlDevice { let slot = await this.getActiveSlot(); console.log("activeSlot:", slot); + let [slotCount, partitions] = await this.getDevicePartitions(); + console.log("isRecognizedDevice:", isRecognizedDevice(slotCount, partitions)); + let blob = await loadFileFromLocal(); await this.flashBlob(flashPartition, blob); - await this.erase(erasePartition); + //await this.erase(erasePartition); + + await this.setActvieSlot("a"); + console.log("resetting") await this.reset(); return true; diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 6dbd52a..d596731 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -1,6 +1,6 @@ import { CommandHandler, cmd_t, sahara_mode_t, status_t, exec_cmd_t } from "./saharaDefs" -import { concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; -import config from '@/config' +import { containsBytes, concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; +import config from "@/config" export class Sahara { cdc; @@ -18,6 +18,7 @@ export class Sahara { this.ch = new CommandHandler(); // TODO: change to auto upload Loader this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; + //this.programmer = "6000000000010000_f8ab20526358c4fa_fhprg.bin" this.id = null; this.serial = ""; this.mode = ""; @@ -171,7 +172,7 @@ export class Sahara { try { let processed = 0; - const contentLength = +response.headers.get('Content-Length'); + //const contentLength = +response.headers.get('Content-Length'); const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index b98c8f1..10ba0ba 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -1,99 +1,117 @@ -import { concatUint8Array, loadFileFromLocal } from "./utils"; - +import { concatUint8Array, readBlobAsBuffer } from "./utils"; const FILE_MAGIC = 0xed26ff3a; -const FILE_HEADER_SIZE = 28; +export const FILE_HEADER_SIZE = 28; const CHUNK_HEADER_SIZE = 12; -export const ChunkType = { - Raw : 0xcac1, - Fill : 0xcac2, - Skip : 0xcac3, - Crc32 : 0xcac4, +const ChunkType = { + Raw : 0xCAC1, + Fill : 0xCAC2, + Skip : 0xCAC3, + Crc32 : 0xCAC4, } - -export class QCSparse { - constructor(blob) { - this.blob = blob - this.offset = 0; - this.major_version = null; - this.minor_version = null; - this.file_hdr_sz = null; - this.chunk_hdr_sz = null; - this.blk_sz = null; - this.total_blks = null; - this.total_chunks = null; - this.image_checksum = null; - this.blobOffset = 0; +async function parseChunkHeader(blobChunkHeader) { + let chunkHeader = await readBlobAsBuffer(blobChunkHeader); + let view = new DataView(chunkHeader); + return { + type : view.getUint16(0, true), + blocks : view.getUint32(4, true), + dataBytes : view.getUint32(8, true) - CHUNK_HEADER_SIZE, + data : null, } +} - parseFileHeader() { - let header = this.blob.slice(0, FILE_HEADER_SIZE); - let view = new DataView(header); +export async function parseFileHeader(blobHeader) { + let header = await readBlobAsBuffer(blobHeader); + let view = new DataView(header); - let magic = view.getUint32(0, true); - this.major_version = view.getUint16(4, true); - this.minor_version = view.getUint16(6, true); - this.file_hdr_sz = view.getUint16(8, true); - this.chunk_hdr_sz = view.getUint16(10, true); - this.blk_sz = view.getUint32(12, true); - this.total_blks = view.getUint32(16, true); - this.total_chunks = view.getUint32(20, true); - this.image_checksum = view.getUint32(24, true); + let magic = view.getUint32(0, true); + let major_version = view.getUint16(4, true); + let minor_version = view.getUint16(6, true); + let file_hdr_sz = view.getUint16(8, true); + let chunk_hdr_sz = view.getUint16(10, true); + let blk_sz = view.getUint32(12, true); + let total_blks = view.getUint32(16, true); + let total_chunks = view.getUint32(20, true); + let crc32 = view.getUint32(24, true); - if (magic != FILE_MAGIC) { - return false; - } - if (this.file_hdr_sz != FILE_MAGIC) { - console.error(`The file header size was expected to be 28, but is ${this.file_hdr_sz}.`); - return false; - } - if (this.chunk_hdr_sz != CHUNK_HEADER_SIZE) { - console.error(`The chunk header size was expected to be 12, but is ${this.chunk_hdr_sz}.`); - return false; - } - console.log("Sparse format detected. USing unpacked iamge."); - return true; + if (magic != FILE_MAGIC) { + return null; } + if (file_hdr_sz != FILE_HEADER_SIZE) { + console.error(`The file header size was expected to be 28, but is ${this.file_hdr_sz}.`); + return null; + } + if (chunk_hdr_sz != CHUNK_HEADER_SIZE) { + console.error(`The chunk header size was expected to be 12, but is ${this.chunk_hdr_sz}.`); + return null; + } + + //console.log("Sparse format detected. Using unpacked image."); + return { + magic : magic, + major_version : major_version, + minor_version : minor_version, + file_hdr_sz : file_hdr_sz, + chunk_hdr_sz : chunk_hdr_sz, + blk_sz : blk_sz, + total_blks : total_blks, + total_chunks : total_chunks, + crc32 : crc32, + } +} +export class QCSparse { + constructor(blob, header) { + this.blob = blob; + this.offset = 0; + this.major_version = header.major_version; + this.minor_version = header.minor_version + this.file_hdr_sz = header.file_hdr_sz; + this.chunk_hdr_sz = header.chunk_hdr_sz; + this.blk_sz = header.blk_sz; + this.total_blks = header.total_blks; + this.total_chunks = header.total_chunks; + this.crc32 = header.crc32; + this.blobOffset = 0; + this.tmpdata = new Uint8Array(0); + } - getChunkSize() { + async getChunkSize() { if (this.total_blks < this.offset) { console.error("Unmached output blocks"); return -1; } - let chunkHeader = this.blob.slice(this.blobOffset, CHUNK_HEADER_SIZE); - let view = new DataView(chunkHeader); - const chunk_type = view.getUint16(0, true); - const chunk_sz = view.getUint32(4, true); - const total_sz = view.getUint32(8, true); - const data_sz = total_sz - 12; + + let chunkHeader = await parseChunkHeader(this.blob.slice(this.blobOffset, this.blobOffset + CHUNK_HEADER_SIZE)); + const chunk_type = chunkHeader.type; + const blocks = chunkHeader.blocks; + const data_sz = chunkHeader.dataBytes; + this.blobOffset += CHUNK_HEADER_SIZE + data_sz; if (chunk_type == ChunkType.Raw) { - if (data_sz != (chunk_sz*this.blk_sz)) { + if (data_sz != (blocks*this.blk_sz)) { console.error("Rase chunk input size does not match output size"); return -1; } else { - this.blobOffset += chunk_sz * this.blk_sz; - return chunk_sz * this.blk_sz; + return data_sz; } } else if (chunk_type == ChunkType.Fill) { if (data_sz != 4) { - console.error("Fill chunk shoudl have 4 bytes of fill"); + console.error("Fill chunk should have 4 bytes of fill"); return -1; } else { - return Math.floor((chunk_sz * this.blk_sz)/4); + return blocks * this.blk_sz; } } else if (chunk_type == ChunkType.Skip) { - return chunk_sz * this.blk_sz; + return blocks * this.blk_sz; } else if (chunk_type == ChunkType.Crc32) { if (data_sz != 4) { console.error("CRC32 chunk should have 4 bytes of CRC"); return -1; } else { - this.blobOffset += 4; return 0; } } else { @@ -103,11 +121,11 @@ export class QCSparse { } - getSize() { - this.blobOffset += FILE_HEADER_SIZE; + async getSize() { + this.blobOffset = FILE_HEADER_SIZE; let length = 0, chunk = 0; while (chunk < this.total_chunks) { - let tlen = this.getChunkSize(); + let tlen = await this.getChunkSize(); if (tlen == -1) break; length += tlen; @@ -118,25 +136,26 @@ export class QCSparse { } - unsparse() { + async unsparse() { if (this.total_blks < this.offset) { console.error("Error while unsparsing"); return -1; } - let chunkHeader = this.blob.slice(this.blobOffset, CHUNK_HEADER_SIZE); - let view = new DataView(chunkHeader); - const chunk_type = view.getUint16(0, true); - const chunk_sz = view.getUint32(4, true); - const total_sz = view.getUint32(8, true); - const data_sz = total_sz - 12; + + + let chunkHeader = await parseChunkHeader(this.blob.slice(this.blobOffset, this.blobOffset += CHUNK_HEADER_SIZE)) + const chunk_type = chunkHeader.type; + const blocks = chunkHeader.blocks; + const data_sz = chunkHeader.dataBytes; if (chunk_type == ChunkType.Raw) { - if (data_sz != (chunk_sz*this.blk_sz)) { + if (data_sz != (blocks*this.blk_sz)) { console.error("Rase chunk input size does not match output size"); return -1; } else { - let data = this.blob.slice(this.blobOffset, this.blobOffset += chunk_sz * this.blk_sz); - this.offset += chunk_sz; + const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += data_sz)); + const data = new Uint8Array(buffer); + this.offset += blocks; return data; } } else if (chunk_type == ChunkType.Fill) { @@ -144,26 +163,28 @@ export class QCSparse { console.error("Fill chunk should have 4 bytes of fill"); return -1; } else { - let fill_bin = new Uint8Array(this.blob.slice(this.blobOffset, this.blobOffset += 4)); - const repetitions = Math.floor((chunk_sz * this.blk_sz)/4); - let data; - for (let i = 0; i < repetitions; i++) { - data = concatUint8Array([data, fill_bin]); + const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += 4)); + let fill_bin = new Uint8Array(buffer); + + const repetitions = Math.floor((blocks*this.blk_sz)/4); + let data = new Uint8Array(blocks*this.blk_sz); + for (let i = 0; i < blocks*this.blk; i+=4) { + data.set(fill_bin, i); } - this.offset += chunk_sz; - return data.buffer; + this.offset += blocks; + return data; } } else if (chunk_type == ChunkType.Skip) { - let data = new ArrayBuffer(chunk_sz*this.blk_sz).fill(0x00); - this.offset += chunk_sz; - return data; + let byteToSend = blocks*this.blk_sz; + this.offset += blocks; + return new Uint8Array(byteToSend).fill(0x00); } else if (chunk_type == ChunkType.Crc32) { if (data_sz != 4) { console.error("CRC32 chunk should have 4 bytes of CRC"); return -1; } else { this.blobOffset += 4; - return new ArrayBuffer(0); + return new Uint8Array(0); } } else { console.error("Unknown chunk type"); @@ -172,17 +193,19 @@ export class QCSparse { } - read(length=null) { + async read(length=null) { let tdata; + this.blobOffset = FILE_HEADER_SIZE; if (length === null) - return this.unsparse(); + return await this.unsparse(); if (length <= this.tmpdata.length) { tdata = this.tmpdata.slice(0, length); this.tmpdata = this.tmpdata.slice(length); return tdata; } while (this.tmpdata.length < length) { - this.tmpdata = concatUint8Array([this.tmpdata, new Uint8Array(this.unsparse())]) + let addedData = await this.unsparse(); + this.tmpdata = concatUint8Array([this.tmpdata, addedData]); if (length <= this.tmpdata.length) { tdata = this.tmpdata.slice(0, length); this.tmpdata = this.tmpdata.slice(length); @@ -191,3 +214,157 @@ export class QCSparse { } } } + + +class BlobBuilder { + constructor(type) { + this.type = type; + this.blob = new Blob([], { type: this.type }); + } + + append(blob) { + this.blob = new Blob([this.blob, blob], { type: this.type }); + } + + getBlob() { + return this.blob; + } +} + + +async function createImage(header, chunks) { + let blobBuilder = new BlobBuilder(); + + let buffer = new ArrayBuffer(FILE_HEADER_SIZE); + let dataView = new DataView(buffer); + let arrayView = new Uint8Array(buffer); + + dataView.setUint32(0, FILE_MAGIC, true); + // v1.0 + dataView.setUint16(4, header.major_version, true); + dataView.setUint16(6, header.minor_version, true); + dataView.setUint16(8, header.file_hdr_sz, true); + dataView.setUint16(10, header.chunk_hdr_sz, true); + + // Match input parameters + //TODO: multiple chunks in a split + dataView.setUint32(12, header.blk_sz, true); + dataView.setUint32(16, chunks[0].blocks, true); + dataView.setUint32(20, chunks.length, true); + + dataView.setUint32(24, 0, true); + + blobBuilder.append(new Blob([buffer])); + for (let chunk of chunks) { + let isChunkTypeSkip = chunk.data == null; + buffer = new ArrayBuffer(CHUNK_HEADER_SIZE + (isChunkTypeSkip ? 0 : chunk.data.size)); + dataView = new DataView(buffer); + arrayView = new Uint8Array(buffer); + + dataView.setUint16(0, chunk.type, true); + dataView.setUint16(2, 0, true); // reserved + dataView.setUint32(4, chunk.blocks, true); + dataView.setUint32( + 8, + CHUNK_HEADER_SIZE + (isChunkTypeSkip ? 0 : chunk.data.size), + true + ); + + let chunkArrayView; + if (!isChunkTypeSkip) { + chunkArrayView = new Uint8Array(await readBlobAsBuffer(chunk.data)); + } else { + chunkArrayView = new Uint8Array(0); + } + arrayView.set(chunkArrayView, CHUNK_HEADER_SIZE); + blobBuilder.append(new Blob([buffer])); + } + + return blobBuilder.getBlob(); +} + + +const MAX_DOWNLOAD_SIZE = 1024 * 1024 * 1024; // 1 GiB + +function calcChunksRealDataBytes(chunk, blockSize) { + switch (chunk.type) { + case ChunkType.Raw: + return chunk.dataBytes; + case ChunkType.Fill: + return chunk.blocks * blockSize; + case ChunkType.Skip: + return chunk.blocks * blockSize; + case ChunkType.Crc32: + return 0; + default: + return null; + } +} + + +export async function* splitBlob(blob, splitSize = 1048576) { + const safeToSend = splitSize; + + if (blob.size <= MAX_DOWNLOAD_SIZE) { + yield blob; + return; + } + + let header = await parseFileHeader(blob.slice(0, FILE_HEADER_SIZE)); + header.crc32 = 0; + blob = blob.slice(FILE_HEADER_SIZE); + + for (let i = 0; i < header.total_chunks; i++) { + let originalChunk = await parseChunkHeader(blob.slice(0, CHUNK_HEADER_SIZE)); + originalChunk.data = blob.slice(CHUNK_HEADER_SIZE, CHUNK_HEADER_SIZE + originalChunk.dataBytes); + blob = blob.slice(CHUNK_HEADER_SIZE + originalChunk.dataBytes); + + let chunksToProcess = []; + let realBytesToWrite = calcChunksRealDataBytes(originalChunk, header.blk_sz) + + const isChunkTypeSkip = originalChunk.type == ChunkType.Skip; + const isChunkTypeFill = originalChunk.type == ChunkType.Fill; + + if (realBytesToWrite > safeToSend) { + + let bytesToWrite = isChunkTypeSkip ? 1 : originalChunk.dataBytes; + let originalChunkData = originalChunk.data; + + while (bytesToWrite > 0) { + const toSend = Math.min(safeToSend, bytesToWrite); + let tmpChunk; + + if (isChunkTypeFill || isChunkTypeSkip) { + while (realBytesToWrite > 0) { + const realSend = Math.min(safeToSend, realBytesToWrite); + tmpChunk = { + type : originalChunk.type, + blocks : realSend / header.blk_sz, + dataBytes : isChunkTypeSkip ? 0 : toSend, + data : isChunkTypeSkip ? null : originalChunkData.slice(0, toSend), + } + chunksToProcess.push(tmpChunk); + realBytesToWrite -= realSend; + } + } else { + tmpChunk = { + type : originalChunk.type, + blocks : toSend / header.blk_sz, + dataBytes : isChunkTypeSkip ? 0 : toSend, + data : isChunkTypeSkip ? null : originalChunkData.slice(0, toSend), + } + chunksToProcess.push(tmpChunk); + } + + bytesToWrite -= toSend; + originalChunkData = originalChunkData?.slice(toSend); + } + } else { + chunksToProcess.push(originalChunk) + } + for (const chunk of chunksToProcess) { + let splitImage = await createImage(header, [chunk]); + yield splitImage; + } + } +} diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 4cf4e1d..d1a40da 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -69,7 +69,7 @@ export class usbClass { try { await this.device?.open(); await this.device?.selectConfiguration(1); - await this.device?.claimInterface(this.device.configuration.interfaces[0].interfaceNumber); + await this.device?.claimInterface(0); } catch (error) { throw error; } diff --git a/src/QDL/utils.js b/src/QDL/utils.js index 12a31aa..c5e0ef2 100644 --- a/src/QDL/utils.js +++ b/src/QDL/utils.js @@ -78,4 +78,13 @@ export function readBlobAsBuffer(blob) { }); } +export function fromUint8ArrayToNumber(array) { + let view = new DataView(array.buffer, 0); + if (array.length > 4) { + console.error("Only returns <= 32 bit number"); + return null; + } + return view.getUint32(0, true); +} + export const sleep = ms => new Promise(r => setTimeout(r, ms)); From 59ea98074146198e13ff0914ca70260508f280e3 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 03:51:58 -0400 Subject: [PATCH 035/112] transferout with retry --- src/QDL/firehose.js | 1 + src/QDL/qdlDevice.js | 9 +++++---- src/QDL/sparse.js | 7 +++++++ src/QDL/usblib.js | 23 +++++++++++++++++++---- 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index f9c14c1..2e86c68 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -398,6 +398,7 @@ export class Firehose { offset += wlen; bytesToWriteSplit -= wlen; bytesWritten += wlen; + console.log(total - bytesWritten) onProgress(bytesWritten/total); //console.log("progress:", total - bytesWritten); diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 2eac2fd..5de2949 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -274,23 +274,24 @@ export class qdlDevice { // TODO: run() is for testing, will be deleted so that qdl.js is a module async run() { try { - let flashPartition = "system_a"; + let flashPartition = "system_"; let erasePartition = "cache"; await this.toCmdMode(); let slot = await this.getActiveSlot(); console.log("activeSlot:", slot); + let newSlot = slot === "a" ? "b" : "a" let [slotCount, partitions] = await this.getDevicePartitions(); console.log("isRecognizedDevice:", isRecognizedDevice(slotCount, partitions)); - let blob = await loadFileFromLocal(); - await this.flashBlob(flashPartition, blob); + //let blob = await loadFileFromLocal(); + //await this.flashBlob(flashPartition+newSlot, blob); //await this.erase(erasePartition); - await this.setActvieSlot("a"); + //await this.setActvieSlot(newSlot); console.log("resetting") await this.reset(); diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index 10ba0ba..1b350fc 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -311,9 +311,16 @@ export async function* splitBlob(blob, splitSize = 1048576) { } let header = await parseFileHeader(blob.slice(0, FILE_HEADER_SIZE)); + if (header === null) { + yield blob; + return; + } + header.crc32 = 0; blob = blob.slice(FILE_HEADER_SIZE); + + for (let i = 0; i < header.total_chunks; i++) { let originalChunk = await parseChunkHeader(blob.slice(0, CHUNK_HEADER_SIZE)); originalChunk.data = blob.slice(CHUNK_HEADER_SIZE, CHUNK_HEADER_SIZE + originalChunk.dataBytes); diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index d1a40da..80af619 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -141,9 +141,21 @@ export class usbClass { pktSize = cmdPacket.length; } - if (cmdPacket.length === 0 && force) - await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); + if (cmdPacket.length === 0 && force) { + try { + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); + } catch(error) { + try { + await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); + } catch(error) { + console.error(error); + return false; + } + } + return true; + } + let retry = 0; while (offset < cmdPacket.length){ try { if (wait) { @@ -154,8 +166,11 @@ export class usbClass { } offset += pktSize; } catch (error) { - console.error(error); - return false; + retry += 1; + if (retry == 3) { + console.error(error); + return false; + } } } return true; From 1d33e5d4631b745bda930af726c974f8ebe68413 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 04:05:45 -0400 Subject: [PATCH 036/112] add reset userdata --- src/QDL/qdlDevice.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 5de2949..4bbc5e9 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -137,6 +137,33 @@ export class qdlDevice { } + async resetUserdata() { + if (this.mode !== "firehose") { + console.error("Please try again, must be in command mode to flash") + return false; + } + + let dp = await this.firehose?.detectPartition("userdata"); + const found = dp[0]; + if (found) { + const lun = dp[0], partition = dp[1]; + const wData = new TextEncoder().encode("COMMA_ABL_RESET"); + const startSector = partition.sector; + console.log("Writing reset flag to partition \"userdata\""); + if (await this.firehose.cmdProgram(lun, startSector, new Blob(wData.buffer, onProgress))) { + console.log("Successfully writing reset flag to userdata"); + } else { + console.error("Error writing reset flag to userdata"); + return false; + } + } else { + console.error("Can't find partition userdata"); + return false; + } + return true; + } + + async getDevicePartitions() { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode to get device partitions info"); From c3986eb61a9e68a04fa26909880704c8a1b1f8a1 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 04:08:59 -0400 Subject: [PATCH 037/112] add semicolon --- src/QDL/gpt.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/QDL/gpt.js b/src/QDL/gpt.js index 3804918..0fe2433 100644 --- a/src/QDL/gpt.js +++ b/src/QDL/gpt.js @@ -299,15 +299,15 @@ export class gpt { const headeroffset = this.header.current_lba * this.sectorSize; let headerdata = Uint8Array.from(data.slice(headeroffset, headeroffset+this.header.header_size)); - let view = new DataView(new ArrayBuffer(4)) - view.setInt32(0, CRC32.buf(Buffer.from(partdata)), true) + let view = new DataView(new ArrayBuffer(4)); + view.setInt32(0, CRC32.buf(Buffer.from(partdata)), true); headerdata.set(new Uint8Array(view.buffer), 0x58); view.setInt32(0, 0, true); headerdata.set(new Uint8Array(view.buffer) , 0x10); - view.setInt32(0, CRC32.buf(Buffer.from(headerdata)), true) + view.setInt32(0, CRC32.buf(Buffer.from(headerdata)), true); headerdata.set(new Uint8Array(view.buffer), 0x10); - data.set(headerdata, headeroffset) + data.set(headerdata, headeroffset); return data; } } From a71b4bd0a380be3da6941433c5a3aa1770994d11 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 04:33:22 -0400 Subject: [PATCH 038/112] update onprogress --- src/QDL/firehose.js | 16 ++++++++-------- src/QDL/qdl.js | 6 +++--- src/QDL/qdlDevice.js | 8 ++++---- src/QDL/sahara.js | 4 ++-- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 2e86c68..d1599aa 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -347,7 +347,7 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}, test=true) { + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress, test=true) { let total = blob.size; let sparseformat = false; @@ -371,8 +371,7 @@ export class Firehose { ` start_sector=\"${startSector}\" />\n`; let rsp = await this.xmlSend(data); - let bytesWritten = 0; - + let i = 0 for await (let split of Sparse.splitBlob(blob)) { let offset = 0; let bytesToWriteSplit = split.size; @@ -397,11 +396,12 @@ export class Firehose { offset += wlen; bytesToWriteSplit -= wlen; - bytesWritten += wlen; - console.log(total - bytesWritten) - onProgress(bytesWritten/total); - //console.log("progress:", total - bytesWritten); + if (i % 10 === 0) + onProgress((total-bytesToWriteSplit)/total); + i += 1; + + //console.log(total - bytesWritten) if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + @@ -410,7 +410,6 @@ export class Firehose { wdata = concatUint8Array([wdata, fillArray]); } await this.cdc.write(wdata); - //console.log(`Progress: ${Math.floor(offset/total)*100}%`); await this.cdc.write(new Uint8Array(0), null, true, true); } } @@ -429,6 +428,7 @@ export class Firehose { console.error("Error:", resposne); return false; } + onProgress(1.0); return true; } diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index c675c4c..1bdd037 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -39,10 +39,10 @@ export const Error = { REQUIREMENTS_NOT_MET: 8, } -function isRecognizedDevice(maxDownloadSize, slotCount, partitions) { +function isRecognizedDevice(slotCount, partitions) { - if (maxDownloadSize !== 104857600 || slotCount !== 2) { - console.error('[QDL] Unrecognised device (kernel, maxDownloadSize or slotCount)') + if (slotCount !== 2) { + console.error('[QDL] Unrecognised device (kernel, slotCount)') return false } diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 4bbc5e9..9837376 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -73,7 +73,7 @@ export class qdlDevice { } - async flashBlob(partitionName, blob, onProgress) { + async flashBlob(partitionName, blob, onProgress=(_progress)=>{}) { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode to flash") return false; @@ -96,7 +96,7 @@ export class qdlDevice { } startSector = partition.sector; console.log(`Flashing ${partitionName}...`); - if (await this.firehose.cmdProgram(lun, startSector, blob, onProgress)) { + if (await this.firehose.cmdProgram(lun, startSector, blob, (progress) => onProgress(progress))) { console.log(`partition ${partitionName}: startSector ${partition.sector}, sectors ${partition.sectors}`); } else { console.error("Error writing image"); @@ -313,8 +313,8 @@ export class qdlDevice { let [slotCount, partitions] = await this.getDevicePartitions(); console.log("isRecognizedDevice:", isRecognizedDevice(slotCount, partitions)); - //let blob = await loadFileFromLocal(); - //await this.flashBlob(flashPartition+newSlot, blob); + let blob = await loadFileFromLocal(); + await this.flashBlob(flashPartition+newSlot, blob); //await this.erase(erasePartition); diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index d596731..452cd2e 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -17,8 +17,8 @@ export class Sahara { this.version = null; this.ch = new CommandHandler(); // TODO: change to auto upload Loader - this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; - //this.programmer = "6000000000010000_f8ab20526358c4fa_fhprg.bin" + //this.programmer = "0008e0e100000000_afca69d4235117e5_fhprg.bin"; + this.programmer = "6000000000010000_f8ab20526358c4fa_fhprg.bin" this.id = null; this.serial = ""; this.mode = ""; From 78cc38a560fc13abaa87a09c82438da6a8626409 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 12:40:29 -0400 Subject: [PATCH 039/112] test --- src/QDL/qdl.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 1bdd037..ad23ad1 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -11,6 +11,9 @@ import { useImageWorker } from '@/QDL/image' import { createManifest } from '@/QDL/manifest' import { withProgress } from '@/QDL/progress' +// TODO: remove after upload to cloud +import { loadFileFromLocal } from './utils.js' + /** * @typedef {import('./manifest.js').Image} Image */ @@ -255,13 +258,21 @@ export function useQdl() { } for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { - const fileHandle = await imageWorker.current.getImage(image) - const blob = await fileHandle.getFile() - if (image.sparse) { - setMessage(`Erasing ${image.name}`) - await qdl.current.erase(image.name) + // TODO: remove manual upload after uploaded to cloud + let blob; + if (image.name !== "system") { + const fileHandle = await imageWorker.current.getImage(image) + blob = await fileHandle.getFile() + } else { + blob = await loadFileFromLocal(); } + + //if (image.sparse) { + // setMessage(`Erasing ${image.name}`) + // await qdl.current.erase(image.name) + //} + setMessage(`Flashing ${image.name}`) await qdl.current.flashBlob(image.name, blob, onProgress) } @@ -289,7 +300,9 @@ export function useQdl() { async function eraseDevice() { setMessage('Erasing userdata') - await qdl.current.erase("userdata") + // TODO: revert for this to work + //await qdl.current.erase("userdata") + //await qdl.current.resetUserdata() setProgress(0.9) setMessage('Rebooting') From 7f2ca360ef09d34e5a6d2b55fb2b6472f9b89fea Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Thu, 14 Mar 2024 12:54:16 -0400 Subject: [PATCH 040/112] qdl update --- src/QDL/qdl.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index ad23ad1..88379d8 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -268,13 +268,15 @@ export function useQdl() { blob = await loadFileFromLocal(); } + // TODO: delete this. writing full image in qdl regardless of sparse or non-sparse //if (image.sparse) { // setMessage(`Erasing ${image.name}`) // await qdl.current.erase(image.name) //} setMessage(`Flashing ${image.name}`) - await qdl.current.flashBlob(image.name, blob, onProgress) + const partitionName = image.name + `_${currentSlot}`; + await qdl.current.flashBlob(partitionName, blob, onProgress) } console.debug('[QDL] Flashed all partitions') From 7987cfbce90702d3553f410fdbc946e1b6db41f5 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 15 Mar 2024 00:39:29 -0400 Subject: [PATCH 041/112] fix sparse --- src/QDL/firehose.js | 104 ++++++++++++++++++++++--------------------- src/QDL/qdl.js | 26 +++++------ src/QDL/qdlDevice.js | 3 +- src/QDL/sparse.js | 18 ++++---- src/QDL/usblib.js | 4 +- 5 files changed, 76 insertions(+), 79 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index d1599aa..1dd7876 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -370,63 +370,65 @@ export class Firehose { ` physical_partition_number=\"${physicalPartitionNumber}\"` + ` start_sector=\"${startSector}\" />\n`; let rsp = await this.xmlSend(data); + let i = 0, bytesWritten = 0; - let i = 0 - for await (let split of Sparse.splitBlob(blob)) { - let offset = 0; - let bytesToWriteSplit = split.size; - let sparseSplit; - - if (sparseformat) { - let sparseSplitHeader = await Sparse.parseFileHeader(split.slice(0, Sparse.FILE_HEADER_SIZE)); - sparseSplit = new Sparse.QCSparse(split, sparseSplitHeader); - bytesToWriteSplit = await sparseSplit.getSize(); - } - - if (rsp.resp) { - while (bytesToWriteSplit > 0) { - let wlen = Math.min(bytesToWriteSplit, this.cfg.MaxPayloadSizeToTargetInBytes); - let wdata; - - if (sparseformat) { - wdata = await sparseSplit?.read(wlen); - } else { - wdata = new Uint8Array(await readBlobAsBuffer(split.slice(offset, offset + wlen))); - } - - offset += wlen; - bytesToWriteSplit -= wlen; - - if (i % 10 === 0) - onProgress((total-bytesToWriteSplit)/total); - i += 1; - - //console.log(total - bytesWritten) + if (rsp.resp) { + for await (let split of Sparse.splitBlob(blob)) { + let offset = 0; + let bytesToWriteSplit = split.size; + let sparseSplit; + + if (sparseformat) { + let sparseSplitHeader = await Sparse.parseFileHeader(split.slice(0, Sparse.FILE_HEADER_SIZE)); + sparseSplit = new Sparse.QCSparse(split, sparseSplitHeader); + bytesToWriteSplit = await sparseSplit.getSize(); + } - if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ - let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + - this.cfg.SECTOR_SIZE_IN_BYTES; - const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); - wdata = concatUint8Array([wdata, fillArray]); + while (bytesToWriteSplit > 0) { + let wlen = Math.min(bytesToWriteSplit, this.cfg.MaxPayloadSizeToTargetInBytes); + let wdata; + if (sparseformat) { + wdata = await sparseSplit?.read(wlen); + } else { + wdata = new Uint8Array(await readBlobAsBuffer(split.slice(offset, offset + wlen))); + } + if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ + let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + + this.cfg.SECTOR_SIZE_IN_BYTES; + const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); + wdata = concatUint8Array([wdata, fillArray]); + } + await this.cdc.write(wdata); + await this.cdc.write(new Uint8Array(0), null, true, true); + // ??? why do I need this for sparse? + if (sparseformat && bytesWritten < total) + await this.cdc.write(new Uint8Array(0), null, true, true); + + if (i % 10 === 0) + onProgress((total-bytesToWriteSplit)/total); + i += 1; + offset += wlen; + bytesToWriteSplit -= wlen; + bytesWritten += wlen; + + // TODO:delete + console.log(total - bytesWritten) } - await this.cdc.write(wdata); - await this.cdc.write(new Uint8Array(0), null, true, true); } - } - } - console.log("waiting"); - const wd = await this.waitForData(); - console.log("finish waiting") - const log = this.xml.getLog(wd); - const resposne = this.xml.getReponse(wd); - if (resposne.hasOwnProperty("value")) { - if (resposne["value"] !== "ACK") { - console.error("ERROR") + console.log("waiting"); + const wd = await this.waitForData(); + console.log("finish waiting") + const log = this.xml.getLog(wd); + const resposne = this.xml.getReponse(wd); + if (resposne.hasOwnProperty("value")) { + if (resposne["value"] !== "ACK") { + console.error("ERROR") + return false; + } + } else { + console.error("Error:", resposne); return false; } - } else { - console.error("Error:", resposne); - return false; } onProgress(1.0); return true; diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 88379d8..b85633e 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -12,7 +12,7 @@ import { createManifest } from '@/QDL/manifest' import { withProgress } from '@/QDL/progress' // TODO: remove after upload to cloud -import { loadFileFromLocal } from './utils.js' +import { loadFileFromLocal } from '@/QDL/utils.js' /** * @typedef {import('./manifest.js').Image} Image @@ -45,7 +45,7 @@ export const Error = { function isRecognizedDevice(slotCount, partitions) { if (slotCount !== 2) { - console.error('[QDL] Unrecognised device (kernel, slotCount)') + console.error('[QDL] Unrecognised device (slotCount)') return false } @@ -168,8 +168,7 @@ export function useQdl() { console.info('[QDL] Connected') return qdl.current.getDevicePartitions() .then(([slotCount, partitions]) => { - const maxDownloadSize = qdl.current.firehose.cfg.MaxPayloadSizeToTargetInBytes; - const recognized = isRecognizedDevice(maxDownloadSize, slotCount, partitions) + const recognized = isRecognizedDevice(slotCount, partitions) console.debug('[QDL] Device info', { recognized, partitions}) if (!recognized) { @@ -228,7 +227,8 @@ export function useQdl() { async function unpackImages() { for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { setMessage(`Unpacking ${image.name}`) - await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) + if (image.name !== "system") + await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) } } @@ -256,17 +256,16 @@ export function useQdl() { if (!['a', 'b'].includes(currentSlot)) { throw `Unknown current slot ${currentSlot}` } + const otherSlot = currentSlot === 'a' ? 'b' : 'a' for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { // TODO: remove manual upload after uploaded to cloud - let blob; - if (image.name !== "system") { - const fileHandle = await imageWorker.current.getImage(image) - blob = await fileHandle.getFile() - } else { - blob = await loadFileFromLocal(); - } + const fileHandle = await imageWorker.current.getImage(image) + const blob = await fileHandle.getFile() + + if (image.name == "system") + continue; // TODO: delete this. writing full image in qdl regardless of sparse or non-sparse //if (image.sparse) { @@ -275,12 +274,11 @@ export function useQdl() { //} setMessage(`Flashing ${image.name}`) - const partitionName = image.name + `_${currentSlot}`; + const partitionName = image.name + `_${otherSlot}`; await qdl.current.flashBlob(partitionName, blob, onProgress) } console.debug('[QDL] Flashed all partitions') - const otherSlot = currentSlot === 'a' ? 'b' : 'a' setMessage(`Changing slot to ${otherSlot}`) await qdl.current.setActvieSlot(otherSlot); } diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 9837376..d60437a 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -318,9 +318,8 @@ export class qdlDevice { //await this.erase(erasePartition); - //await this.setActvieSlot(newSlot); + await this.setActvieSlot(newSlot); - console.log("resetting") await this.reset(); return true; diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index 1b350fc..8750764 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -11,7 +11,7 @@ const ChunkType = { Crc32 : 0xCAC4, } -async function parseChunkHeader(blobChunkHeader) { +export async function parseChunkHeader(blobChunkHeader) { let chunkHeader = await readBlobAsBuffer(blobChunkHeader); let view = new DataView(chunkHeader); return { @@ -163,21 +163,19 @@ export class QCSparse { console.error("Fill chunk should have 4 bytes of fill"); return -1; } else { - const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += 4)); + const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += data_sz)); let fill_bin = new Uint8Array(buffer); - - const repetitions = Math.floor((blocks*this.blk_sz)/4); - let data = new Uint8Array(blocks*this.blk_sz); - for (let i = 0; i < blocks*this.blk; i+=4) { + const bufferSize = blocks*this.blk_sz; + let data = new Uint8Array(bufferSize); + for (let i = 0; i < bufferSize; i+=4) data.set(fill_bin, i); - } this.offset += blocks; return data; } } else if (chunk_type == ChunkType.Skip) { let byteToSend = blocks*this.blk_sz; this.offset += blocks; - return new Uint8Array(byteToSend).fill(0x00); + return new Uint8Array(byteToSend).fill(0); } else if (chunk_type == ChunkType.Crc32) { if (data_sz != 4) { console.error("CRC32 chunk should have 4 bytes of CRC"); @@ -302,8 +300,8 @@ function calcChunksRealDataBytes(chunk, blockSize) { } -export async function* splitBlob(blob, splitSize = 1048576) { - const safeToSend = splitSize; +export async function* splitBlob(blob, splitSize = 104857600) { + const safeToSend = splitSize * 7/8; if (blob.size <= MAX_DOWNLOAD_SIZE) { yield blob; diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 80af619..6e47945 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -156,13 +156,13 @@ export class usbClass { } let retry = 0; - while (offset < cmdPacket.length){ + while (offset < cmdPacket.length) { try { if (wait) { await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); } else { this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket.slice(offset, offset + pktSize)); - await sleep(80); + await sleep(80); } offset += pktSize; } catch (error) { From d7eb9162bdf1e89b3ace33024b05e2f15cb038be Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 15 Mar 2024 03:44:12 -0400 Subject: [PATCH 042/112] works --- src/QDL/firehose.js | 21 +++++++++++---------- src/QDL/qdl.js | 9 --------- src/QDL/sparse.js | 4 ++-- src/QDL/usblib.js | 1 + 4 files changed, 14 insertions(+), 21 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 1dd7876..aac591a 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -398,21 +398,22 @@ export class Firehose { const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); wdata = concatUint8Array([wdata, fillArray]); } - await this.cdc.write(wdata); - await this.cdc.write(new Uint8Array(0), null, true, true); - // ??? why do I need this for sparse? + let sts; + sts = await this.cdc.write(wdata); + sts = await this.cdc.write(new Uint8Array(0), null, true, true); + offset += wlen; + bytesToWriteSplit -= wlen; + bytesWritten += wlen; + if (!sts) { + return false; + } + // ??? why do I need this for sparse? maybe because I split and doesn't fill the whole data? if (sparseformat && bytesWritten < total) await this.cdc.write(new Uint8Array(0), null, true, true); if (i % 10 === 0) - onProgress((total-bytesToWriteSplit)/total); + onProgress(bytesWritten/total); i += 1; - offset += wlen; - bytesToWriteSplit -= wlen; - bytesWritten += wlen; - - // TODO:delete - console.log(total - bytesWritten) } } console.log("waiting"); diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index b85633e..3d82b62 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -264,15 +264,6 @@ export function useQdl() { const fileHandle = await imageWorker.current.getImage(image) const blob = await fileHandle.getFile() - if (image.name == "system") - continue; - - // TODO: delete this. writing full image in qdl regardless of sparse or non-sparse - //if (image.sparse) { - // setMessage(`Erasing ${image.name}`) - // await qdl.current.erase(image.name) - //} - setMessage(`Flashing ${image.name}`) const partitionName = image.name + `_${otherSlot}`; await qdl.current.flashBlob(partitionName, blob, onProgress) diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index 8750764..ceaad86 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -300,8 +300,8 @@ function calcChunksRealDataBytes(chunk, blockSize) { } -export async function* splitBlob(blob, splitSize = 104857600) { - const safeToSend = splitSize * 7/8; +export async function* splitBlob(blob, splitSize = 1048576) { + const safeToSend = splitSize; if (blob.size <= MAX_DOWNLOAD_SIZE) { yield blob; diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 6e47945..66e3240 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -168,6 +168,7 @@ export class usbClass { } catch (error) { retry += 1; if (retry == 3) { + await sleep(20); console.error(error); return false; } From fd909546facb3d00243e7d2146468d9721f3686a Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 15 Mar 2024 04:38:55 -0400 Subject: [PATCH 043/112] add loader --- 6000000000010000_f8ab20526358c4fa_fhprg.bin | Bin 0 -> 679953 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 6000000000010000_f8ab20526358c4fa_fhprg.bin diff --git a/6000000000010000_f8ab20526358c4fa_fhprg.bin b/6000000000010000_f8ab20526358c4fa_fhprg.bin new file mode 100644 index 0000000000000000000000000000000000000000..c5b73bb89c67eff5c56d914e08d4504497bd0c74 GIT binary patch literal 679953 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

O0iX$kJZ7TT~+Dz;eb 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¥#>hMouRD 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

    !>SmUBb8oRw23Y&GkLo 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

    rOHuU!b*3kPw z?}OSww8k#l1V6}WT7P%KO@EL3&GqnG4Wd7Y_ZeN}KRgq<1ZJ2=vPs;#*}qQZ^F1lHjvCH>-J{Iv@uA7b$uetMlpZy)yW=|5%dg5)xfg|kQQ_n?o^m_K_#GvKyJ`_ z(0))0FsOf;XK%s2Vk_zmazD@B zu%71mmsv4%pR-{++bxz$#*z`Q`xeB#NnqXZXT_-bzeI6IU(88hYUBX|c2G&oT(JiB z8QvL;C3DOI9hVt7W=0wd^l1xpWDE3g3v_p;1&s!&IhKcT=wfIA<{dT681!M%-n?Ib z1#=y2Ru!ZC**vHz3qXH`y7N^C^Xt&!ZVJO10qcqx$eFQJ4&{Lfg^yv6fnm>MF3&Q; zy^m!icpqb3D3_MvA!P-AX&p}c0<=#-`z9=d8%AxekdieXWqE|+gFmZ6JsGR5g+JCP z$OAnSWt)StJ%aFI8^^HMMS3XXunuQ8!9<&LSVM7Ge{tA95%pBkS0lN8)amT4JTsyX zxPhA-Wn5i2IgAa5b6R&c7YA~K9s<1!Y6l_b)#9EI6V<9;81@?&LmpV`Gwg#f?8`6< z{4DUZz|R6d3;c@VR}8;m_!Yyi7=HQi%ZFb+{PN+K55Ic&)x)nIe)aIH$3B?`%P{oY z_}j!5^8FM>aU75SqJ#!nhIrDcU}&QY!FM5eE(Gs| zh`$hd8BrT>lOs%yFge2H2$NG7nx@5weH0`1FN`;Xu)kwOSuV{GRZ}!gJA*Q9tTf&S z9_`R)jpSrn@YfHIa6!1Ova4KFpVa2#$+R? z0&Th)ln1$kZp}()+!&F+5#fvQ_-r`)9oR0WQ%t8IM7x;rMgIZ(xyaeNuim&vN%R~LRTyz1r;6%!P? z-NUBc!`9uy1^+he__yI?KIgDpw|&^Oeb~Aku9`hw#j|ozwsYHt4{P+;2j{Lf9C&;< zPso&SIdMz2Z8>X~F>)2kyzgrY9vc>vOCwdfM~AsB!>C5prePtP>Y#Szv5;=mQH@^) z6Y~XEGc52E)WN#yVbl6yu9_0Sp2=IQhqq*iRTPto=@8$#cDUf-VeaAKb}h3dZqLtF zTMRv0oXM=?F>Zs5S?*dOTwbbB3JLHDmyaZ6LW1?)VKKv+un}J>g!OKp?_td;ooU&y zF!n$xan>iaTJ-8py_W2YTUBwoCBu9t&$rhex2#pXCl@9c34)<1CqGlLEwJfj`TChF z_6vOQiXCz7OcS(|Pif7s z(jB!;QCT=#HGkM+AKrJ{aKWv^+%3a`e9x`J$8H_YGCA^xb@{{k(zUZPQ^2E4;VfRe zv~3JomA5RY%XSvK>)5LLE@5n@NiZm7?Cy}<0q@;Gt;K6|`@F|z?${A0$ek%Bfki3h zl{1E`emlIoB}pA#s#O$BA3h{!t?fgz_xewDdt%XzqRTphH2ceIpHNo?64(6y=^NGA6L?I6&3QvRRo-?^f~<6lb*}Z zmy@ORIcp-NI$rWlbxL|u%B1R(jfI&3rGpjw;?W7X_+e}OusLwrw42&9H2E27L~WWF zW@%O%n~7c1vaqVrl-{L1=w3yk4}IqX;>{;i=6Al- zî=t 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 apbr9l5a@$I9|Za!&f@0!2bblsf_Ue literal 0 HcmV?d00001 From d5edde88b87f7cfe731c9cfa8ee5cc4836ef9d9f Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 15 Mar 2024 16:09:18 -0400 Subject: [PATCH 044/112] unpack system --- src/QDL/qdl.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 3d82b62..a14fb84 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -227,8 +227,7 @@ export function useQdl() { async function unpackImages() { for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { setMessage(`Unpacking ${image.name}`) - if (image.name !== "system") - await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) + await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) } } From 8fe1e0eca13c6c953fde4dcd9af4f243cba38bbf Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Fri, 15 Mar 2024 23:39:24 -0400 Subject: [PATCH 045/112] remove sleep at write --- src/QDL/usblib.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 66e3240..6e47945 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -168,7 +168,6 @@ export class usbClass { } catch (error) { retry += 1; if (retry == 3) { - await sleep(20); console.error(error); return false; } From 7b874894de737c6df86c7dad7e0af2c9a22b3b36 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 02:39:24 -0400 Subject: [PATCH 046/112] test --- scripts/detach.sh | 5 ++++ scripts/detach_driver.py | 58 ++++++++++++++++++++++++++++++++++++++++ src/app/page.jsx | 9 ++++++- 3 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 scripts/detach.sh create mode 100644 scripts/detach_driver.py diff --git a/scripts/detach.sh b/scripts/detach.sh new file mode 100644 index 0000000..98e85d2 --- /dev/null +++ b/scripts/detach.sh @@ -0,0 +1,5 @@ +sudo pip install pyusb==1.2.1 + +curl -o- https://raw.githubusercontent.com/bongbui321/flash/testing/scripts/detach_driver.py | python3 + +sudo pip uninstall -y pyusb==1.2.1 \ No newline at end of file diff --git a/scripts/detach_driver.py b/scripts/detach_driver.py new file mode 100644 index 0000000..b0ff718 --- /dev/null +++ b/scripts/detach_driver.py @@ -0,0 +1,58 @@ +import sys +import usb.core +import usb.util +import usb.backend.libusb0 +import usb.backend.libusb1 +from ctypes import c_void_p, c_int + +class usb_class: + def __init__(self, portconfig=None): + self.portconfig = portconfig + self.device = None + if sys.platform.startswith('freebsd') or sys.platform.startswith('linux') or sys.platform.startswith('darwin'): + self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.so") + else: + print("Only support Unix-based machine") + sys.exit(1) + if self.backend is not None: + try: + self.backend.lib.libusb_set_option.argtypes = [c_void_p, c_int] + self.backend.lib.libusb_set_option(self.backend.ctx, 1) + except: + self.backend = None + + def detach_driver(self): + devices = usb.core.find(find_all=True, backend=self.backend) + for d in devices: + for usbid in self.portconfig: + if d.idProduct == usbid[1] and d.idVendor == usbid[0]: + self.device = d + break + if self.device is not None: + break + + if self.device is None: + print("Couldn't detect the device. Is it connected ?") + return False + + try: + self.configuration = self.device.get_active_configuration() + except usb.core.USBError as e: + if e.strerror == "Configuration not set": + self.device.set_configuration() + self.configuration = self.device.get_active_configuration() + if e.errno == 13: + self.backend = usb.backend.libusb0.get_backend() + self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid, backend=self.backend) + try: + if self.device.is_kernel_driver_active(0): + print("Detaching kernel driver...") + self.device.detach_kernel_driver(0) + print("Finish detaching kernel driver") + except Exception as err: + print("No kernel driver supported: " + str(err)) + return False + +if __name__ == "__main__": + cdc = usb_class([[0x05c6, 0x9008, -1]]) + cdc.detach_driver() diff --git a/src/app/page.jsx b/src/app/page.jsx index 41104ef..807a62a 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -17,7 +17,7 @@ export default function Home() { console.info(`flash.comma.ai version: ${version}`); return (

    -
    +
    comma

    flash.comma.ai

    @@ -43,6 +43,13 @@ export default function Home() { Another USB-C cable to connect the device to your computer. +

    Connecting for Linux

    + For Linux, run this command in your terminal prior to flashing your device. +
      +
    • + curl -o- https://raw.githubusercontent.com/bongbui321/flash/testing/scripts/detach.sh | bash +
    • +

    USB Driver

    You need additional driver software for Windows before you connect From 37ade70567d0e41f9c11c908184be88883990963 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 03:07:42 -0400 Subject: [PATCH 047/112] update instructions --- src/app/page.jsx | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/app/page.jsx b/src/app/page.jsx index 807a62a..edb8215 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -88,14 +88,13 @@ export default function Home() {


    -

    Fastboot

    -

    Follow these steps to put your device into fastboot mode:

    +

    QDL Mode

    +

    Follow these steps to put your device into QDL mode:

    1. Power off the device and wait for the LEDs to switch off.
    2. +
    3. Connect the device to your computer using the USB-C port (port 2).
    4. Connect power to the OBD-C port (port 1).
    5. -
    6. Then, quickly connect - the device to your computer using the USB-C port (port 2).
    7. -
    8. After a few seconds, the device should indicate it's in fastboot mode and show its serial number.
    9. +
    10. The device then should be visible as an option when choosing the device to flash
    -

    - If your device shows the comma spinner with a loading bar, then it's not in fastboot mode. - Unplug all cables, wait for the device to switch off, and try again. -


    Flashing

    - After your device is in fastboot mode, you can click the button to start flashing. A prompt may appear to - select a device; choose the device labeled "Android". + After your device is in QDL mode, you can click the button to start flashing. A prompt may appear to + select a device; choose the device starts with "QUSB_BULK".

    - The process can take 15+ minutes depending on your internet connection and system performance. Do not + The process can take 30+ minutes depending on your internet connection and system performance. Do not unplug the device until all steps are complete.

    @@ -125,6 +120,10 @@ export default function Home() {

    Troubleshooting

    +

    Too slow

    +

    + It is recommended that you use a USB 3.0 cable when flashing since it will speed up the flashing time by a lot. +

    Cannot enter fastboot or device says "Press any key to continue"

    Try using a different USB cable or USB port. Sometimes USB 2.0 ports work better than USB 3.0 (blue) ports. @@ -133,9 +132,8 @@ export default function Home() {

    My device's screen is blank

    - The device can still be in fastboot mode and reflashed normally if the screen isn't displaying - anything. A blank screen is usually caused by installing older software that doesn't support newer - displays. If a reflash doesn't fix the blank screen, then the device's display may be damaged. + The device screen will be blank in QDL mode, but you can verify that it is in QDL if the device shows up + when you press the Flash icon.

    After flashing, device says unable to mount data partition

    From 84919984733d67b25e11c5a5bb1d53dfe8a1cd0a Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 03:09:47 -0400 Subject: [PATCH 048/112] update instructions --- src/app/page.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/page.jsx b/src/app/page.jsx index edb8215..390f7e8 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -124,7 +124,7 @@ export default function Home() {

    It is recommended that you use a USB 3.0 cable when flashing since it will speed up the flashing time by a lot.

    -

    Cannot enter fastboot or device says "Press any key to continue"

    +

    Cannot enter QDL

    Try using a different USB cable or USB port. Sometimes USB 2.0 ports work better than USB 3.0 (blue) ports. If you're using a USB hub, try connecting the device directly to your computer, or alternatively use a From 5b1c91aa364a5c77460f1cb7fdac5c73b389b479 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 03:18:02 -0400 Subject: [PATCH 049/112] update instructions --- src/QDL/firehose.js | 2 -- src/app/page.jsx | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index aac591a..245f150 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -416,9 +416,7 @@ export class Firehose { i += 1; } } - console.log("waiting"); const wd = await this.waitForData(); - console.log("finish waiting") const log = this.xml.getLog(wd); const resposne = this.xml.getReponse(wd); if (resposne.hasOwnProperty("value")) { diff --git a/src/app/page.jsx b/src/app/page.jsx index 390f7e8..14178be 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -44,7 +44,8 @@ export default function Home() {

    Connecting for Linux

    - For Linux, run this command in your terminal prior to flashing your device. + For Linux, run this command in your terminal prior to flashing your device. + This helps the website to be able to connect to your device.
    • curl -o- https://raw.githubusercontent.com/bongbui321/flash/testing/scripts/detach.sh | bash From 9b3c025692bb5d2ef99fb3d0decee6a97f7ce966 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 13:10:09 -0400 Subject: [PATCH 050/112] move detach --- src/QDL/detach_driver.py | 58 ---------------------------------------- 1 file changed, 58 deletions(-) delete mode 100644 src/QDL/detach_driver.py diff --git a/src/QDL/detach_driver.py b/src/QDL/detach_driver.py deleted file mode 100644 index b0ff718..0000000 --- a/src/QDL/detach_driver.py +++ /dev/null @@ -1,58 +0,0 @@ -import sys -import usb.core -import usb.util -import usb.backend.libusb0 -import usb.backend.libusb1 -from ctypes import c_void_p, c_int - -class usb_class: - def __init__(self, portconfig=None): - self.portconfig = portconfig - self.device = None - if sys.platform.startswith('freebsd') or sys.platform.startswith('linux') or sys.platform.startswith('darwin'): - self.backend = usb.backend.libusb1.get_backend(find_library=lambda x: "libusb-1.0.so") - else: - print("Only support Unix-based machine") - sys.exit(1) - if self.backend is not None: - try: - self.backend.lib.libusb_set_option.argtypes = [c_void_p, c_int] - self.backend.lib.libusb_set_option(self.backend.ctx, 1) - except: - self.backend = None - - def detach_driver(self): - devices = usb.core.find(find_all=True, backend=self.backend) - for d in devices: - for usbid in self.portconfig: - if d.idProduct == usbid[1] and d.idVendor == usbid[0]: - self.device = d - break - if self.device is not None: - break - - if self.device is None: - print("Couldn't detect the device. Is it connected ?") - return False - - try: - self.configuration = self.device.get_active_configuration() - except usb.core.USBError as e: - if e.strerror == "Configuration not set": - self.device.set_configuration() - self.configuration = self.device.get_active_configuration() - if e.errno == 13: - self.backend = usb.backend.libusb0.get_backend() - self.device = usb.core.find(idVendor=self.vid, idProduct=self.pid, backend=self.backend) - try: - if self.device.is_kernel_driver_active(0): - print("Detaching kernel driver...") - self.device.detach_kernel_driver(0) - print("Finish detaching kernel driver") - except Exception as err: - print("No kernel driver supported: " + str(err)) - return False - -if __name__ == "__main__": - cdc = usb_class([[0x05c6, 0x9008, -1]]) - cdc.detach_driver() From bf53ae9ab2ee40759fdf43229f9f0d1c44d9870e Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 13:49:52 -0400 Subject: [PATCH 051/112] cleanup sahara --- src/QDL/sahara.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 452cd2e..dd30de0 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -1,5 +1,5 @@ import { CommandHandler, cmd_t, sahara_mode_t, status_t, exec_cmd_t } from "./saharaDefs" -import { containsBytes, concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; +import { concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; import config from "@/config" export class Sahara { @@ -79,7 +79,7 @@ export class Sahara { try { let data = await this.cdc?.read(); let data_text = new TextDecoder('utf-8').decode(data.data); - if (data.length == 0){ + if (data.length == 0) { return {}; } else if (data_text.includes(" Date: Sat, 16 Mar 2024 14:11:43 -0400 Subject: [PATCH 052/112] update scripts --- scripts/detach.sh | 16 +++++++++++++--- src/app/page.jsx | 2 +- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/scripts/detach.sh b/scripts/detach.sh index 98e85d2..f68b72b 100644 --- a/scripts/detach.sh +++ b/scripts/detach.sh @@ -1,5 +1,15 @@ -sudo pip install pyusb==1.2.1 +output=$(pip list | grep pyusb) +installed="false" +if [[ "$output" == *"pyusb"* ]]; then + installed="true" +fi -curl -o- https://raw.githubusercontent.com/bongbui321/flash/testing/scripts/detach_driver.py | python3 +if [[ "$installed" == "false" ]]; then + pip install pyusb==1.2.1 +fi -sudo pip uninstall -y pyusb==1.2.1 \ No newline at end of file +curl -o- https://raw.githubusercontent.com/bongbui321/flash/qdl/scripts/detach_driver.py | python3 + +if [[ "$installed" == "false" ]]; then + pip uninstall -y pyusb==1.2.1 +fi \ No newline at end of file diff --git a/src/app/page.jsx b/src/app/page.jsx index 14178be..8a0b75c 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -48,7 +48,7 @@ export default function Home() { This helps the website to be able to connect to your device.
      • - curl -o- https://raw.githubusercontent.com/bongbui321/flash/testing/scripts/detach.sh | bash + curl -o- https://raw.githubusercontent.com/bongbui321/flash/qdl/scripts/detach.sh | bash

      USB Driver

      From 8a05f6aecb39b7d7f0467e320008764a882ad6da Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 14:16:04 -0400 Subject: [PATCH 053/112] update instructions --- src/app/page.jsx | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/app/page.jsx b/src/app/page.jsx index 8a0b75c..c1f34d7 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -43,14 +43,6 @@ export default function Home() { Another USB-C cable to connect the device to your computer.
    -

    Connecting for Linux

    - For Linux, run this command in your terminal prior to flashing your device. - This helps the website to be able to connect to your device. -
      -
    • - curl -o- https://raw.githubusercontent.com/bongbui321/flash/qdl/scripts/detach.sh | bash -
    • -

    USB Driver

    You need additional driver software for Windows before you connect @@ -112,6 +104,14 @@ export default function Home() { After your device is in QDL mode, you can click the button to start flashing. A prompt may appear to select a device; choose the device starts with "QUSB_BULK".

    +

    Connecting for Linux

    + For Linux, run this command in your terminal prior to flashing your device. + This helps the website to be able to connect to your device. +
      +
    • + curl -o- https://raw.githubusercontent.com/bongbui321/flash/qdl/scripts/detach.sh | bash +
    • +

    The process can take 30+ minutes depending on your internet connection and system performance. Do not unplug the device until all steps are complete. From 9ad797ebd5a9ff6ef267dc570892a70d0586dd13 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 15:00:47 -0400 Subject: [PATCH 054/112] update error message --- src/QDL/usblib.js | 9 ++++++++- src/app/Flash.jsx | 4 +++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 6e47945..bac41fc 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -69,7 +69,14 @@ export class usbClass { try { await this.device?.open(); await this.device?.selectConfiguration(1); - await this.device?.claimInterface(0); + try { + await this.device?.claimInterface(0); + } catch(error) { + await this.device?.reset(); + await this.device?.forget(); + await this.device?.close(); + throw error; + } } catch (error) { throw error; } diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx index da1de93..4a342f5 100644 --- a/src/app/Flash.jsx +++ b/src/app/Flash.jsx @@ -82,7 +82,9 @@ const errors = { }, [Error.LOST_CONNECTION]: { status: 'Lost connection', - description: 'The connection to your device was lost. Check that your cables are connected properly and try again.', + description: 'The connection to your device was lost. Check that your cables are connected properly and try again. ' + + 'Unplug your device and wait a few seconds. ' + + 'If you are using Linux, make sure to follow the instructions to run a script before flashing.', icon: cable, }, [Error.DOWNLOAD_FAILED]: { From c4067d1c9ded9a2017bc713d9de6dfbc04025204 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 22:26:42 -0400 Subject: [PATCH 055/112] fasttt --- src/QDL/firehose.js | 2 +- src/QDL/usblib.js | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 245f150..c1c891d 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -408,7 +408,7 @@ export class Firehose { return false; } // ??? why do I need this for sparse? maybe because I split and doesn't fill the whole data? - if (sparseformat && bytesWritten < total) + if (sparseformat && bytesWritten < total && wlen < this.cfg.MaxPayloadSizeToTargetInBytes) await this.cdc.write(new Uint8Array(0), null, true, true); if (i % 10 === 0) diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index bac41fc..c282317 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -4,6 +4,8 @@ const vendorID = 0x05c6; const productID = 0x9008; const QDL_USB_CLASS = 0xff; +const BULK_TRANSFER_SIZE = 16384; + export class UsbError extends Error { constructor(message) { super(message); @@ -140,14 +142,6 @@ export class usbClass { } async write(cmdPacket, pktSize=null, wait=true, force=false) { - let offset = 0; - if (pktSize === null) - if (cmdPacket.length > this.epOut?.packetSize){ - pktSize = this.epOut?.packetSize; - } else { - pktSize = cmdPacket.length; - } - if (cmdPacket.length === 0 && force) { try { await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); @@ -163,6 +157,9 @@ export class usbClass { } let retry = 0; + let offset = 0; + if (pktSize === null) + pktSize = BULK_TRANSFER_SIZE; while (offset < cmdPacket.length) { try { if (wait) { From 0972bfb5d342ab95ef69e9f56d9a3b444e82b65c Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 16 Mar 2024 23:21:04 -0400 Subject: [PATCH 056/112] remove run() --- src/QDL/qdlDevice.js | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index d60437a..c6aabc2 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -296,36 +296,4 @@ export class qdlDevice { } return true; } - - - // TODO: run() is for testing, will be deleted so that qdl.js is a module - async run() { - try { - let flashPartition = "system_"; - let erasePartition = "cache"; - - await this.toCmdMode(); - - let slot = await this.getActiveSlot(); - console.log("activeSlot:", slot); - let newSlot = slot === "a" ? "b" : "a" - - let [slotCount, partitions] = await this.getDevicePartitions(); - console.log("isRecognizedDevice:", isRecognizedDevice(slotCount, partitions)); - - let blob = await loadFileFromLocal(); - await this.flashBlob(flashPartition+newSlot, blob); - - //await this.erase(erasePartition); - - await this.setActvieSlot(newSlot); - - await this.reset(); - - return true; - } catch (error) { - console.error(error); - return false; - } - } } From ecca93995a44aa00540d740c010421fe289cb325 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sun, 17 Mar 2024 01:08:05 -0400 Subject: [PATCH 057/112] update eraseuserdata --- src/QDL/firehose.js | 7 ++++--- src/QDL/qdl.js | 4 +++- src/QDL/qdlDevice.js | 6 +++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index c1c891d..2ba90ca 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -347,7 +347,7 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress, test=true) { + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}) { let total = blob.size; let sparseformat = false; @@ -615,7 +615,7 @@ export class Firehose { } - async cmdErase(physicalPartitionNumber, startSector, numPartitionSectors) { + async cmdErase(physicalPartitionNumber, startSector, numPartitionSectors, onProgress) { const data = `\n` + `{}) { if (this.mode !== "firehose") { console.error("Please try again, must be in command mode to erase") return false; @@ -126,7 +126,7 @@ export class qdlDevice { if (guidGpt.partentries.hasOwnProperty(partitionName)) { const partition = guidGpt.partentries[partitionName]; console.log(`Erasing ${partitionName}...`) - await this.firehose.cmdErase(lun, partition.sector, partition.sectors); + await this.firehose.cmdErase(lun, partition.sector, partition.sectors, (progress) => onProgress(progress)); console.log(`Erased ${partitionName} starting at sector ${partition.sector} with sectors ${partition.sectors}`) } else { console.log(`Couldn't erase partition ${partitionName}. Either wrong type or not in lun ${lun}`); @@ -150,7 +150,7 @@ export class qdlDevice { const wData = new TextEncoder().encode("COMMA_ABL_RESET"); const startSector = partition.sector; console.log("Writing reset flag to partition \"userdata\""); - if (await this.firehose.cmdProgram(lun, startSector, new Blob(wData.buffer, onProgress))) { + if (await this.firehose.cmdProgram(lun, startSector, new Blob(wData.buffer))) { console.log("Successfully writing reset flag to userdata"); } else { console.error("Error writing reset flag to userdata"); From 663954f1eff94cce3ff33d633dd5c6a01fec1f74 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Tue, 19 Mar 2024 02:38:00 -0400 Subject: [PATCH 058/112] auto upload loader --- 6000000000010000_f8ab20526358c4fa_fhprg.bin | Bin 679953 -> 0 bytes src/QDL/sahara.js | 20 ++++++++++++++++---- src/config.js | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) delete mode 100644 6000000000010000_f8ab20526358c4fa_fhprg.bin diff --git a/6000000000010000_f8ab20526358c4fa_fhprg.bin b/6000000000010000_f8ab20526358c4fa_fhprg.bin deleted file mode 100644 index c5b73bb89c67eff5c56d914e08d4504497bd0c74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 679953 zcmeEv34Bz=(r;%W1PBl%A}YuML4pRDga83SGT8&!$OMRpP9~X2GB8<~nUEl;VHK5& zsHnJHje9`!qJp9#o2ckTMFB-cK}AJHMMOnK^8VFbXXa!`z|5SVDYRV+rE|aqKKAAe*(Tlks!J>r?qWv_1nrr{pJ%*TCj*@YJKnm zX=1$aJf>@mnUB)ehDau+ADS!EDHt#LPDQ9=J$&*P23T^w^ex1ph3tgd5MMKY z+V#pG<8v1(k2(&FZ`C7ueC+QKV?Dk_T=oI+`TRwGGGDUlSoi1ZrA!8Y6qC>2z9}l5 zjJsc~*mWG3&h2k=IwPkle~edi@^ozUN0q*0hn~M1xjYq~6A~;V)UnYYm8bR|HyMrN z)3HjX2tAt(hWs`2C(2cPKCJlXK7OJ<#1!OzK1E`vCbn!s*)OZ`$h3!;EmN;cP1>=W@D^4Bj^{$vt|2((BE$%$wi5 z`mxRjAD;EH`%FuZQQx1nKkb(6E1s*}da67$B)o8G;~QsJ)SmP8yxt!*4GTTG`nDlj z=@kdgy?x1f>(;C}mH*qTkL32XjDG9>f@s`WZ&+g$Ka=)voCiMQ8H>1DFE}ydXXz$M}s<+k_{{G7BxFGLC zE2IAyQ#IgJ@t?~5z+)?)c=q;Z7lfqVedm;cpO<%;`*l0<*|85&28OIGd%xg`u|F06 z@Zbm2pWL+PrCY*hU%2pJKNMcM=lsaE=XBh8^)D;St{zY_bNfdVW?uKnjSEM;^vcN3 z+PyxwZ;z-CR{S_^cCTl9-Tg{lw~r%Me(u>6eE&D!=6N=cetludeUV)^E?rS}{^Z+l zeRA9T8y~o0U&r`)Q}SOKIbmR%NeAbONe#p|3{;1J2zak^%MJdZ+iMVU;c2-*3`M5IxhBpIC7Hvwmlnvoe_0* zhadiUYqfn}h@-LpBR9P9WDdR;VqP@5Yoi+&qeboY)84_!a$pA~QSeW>$IhpxQ(`?QCGUV6-InLX+A zP9H3~x?~;E8+-jHRfA`}5H$4D)t7bOm)F!grZM-+^W!ql z|GjhcfClTYM++pi} zNX+@D?VAk~hW7h%cGA-9?4v>9%i6Y@htNN`Xv z7UWE$!rEQ5AY;KV9fN|}n@kNIO&!A86)ngJa)g8i2iV?`tcrzyQLUfN=Suu5~;0{se zm|`_k^KYn^{mB5i%#JvjDw)@EoieA6PM|&%Nf9%NKlqUD35y*4%Ub!Vhg1 z7X0M4P3?6-N~cY?4O?_?m&b?PEk4?k^7DY#uPA>y>fA#^E*Uc{WbGr@rhoR)Gr2!L z{?PDt`y7*so_F0ARUg~xBz&6LDSA2fvrcOVey?gZTruQcOUXVB9!Q8x6 z_7}!PKH28WK0#yaUn#nwyx{HIcWUkH9?V;N&AGkav^koVz1jDfw7b82{K4^U4?3QG zv%XEr+`iXLd9r7}7aw?P`OqgCw>^E~+U%m6= z;T?B1E$lXK=~K1WbowxMT}_YIuS_bsd-jbRU#`9Cs>kgO^S?c|>c)$%Zae#{=#h`U z*e_+>k~e}wf<(}RmzqYJdZN60ToBsL)U`fp^(X&cRs7s%6Kwa_efh8Gf6Uvlxo?vx zf*87lwlSe|3UpW4I){da1h=jKiya*`5+r(bdMapA?v3eJE~=RGz@devJ4;Phzdfk@ z)kixAjeE1<%j0*wckTUilD(-p_DSu>FLMk%`|zhPk4dlY^30y#OD?JJ`S0)6brjdH zTrxjn>W}x2Yx@1UHN)QiWm?E5Iia0*&FnBgYkJ+n+7DNEf9L9RH>8g0GVYbf!`nl9lCn*>gTg=8F1x`T}Qt6LiDDDN#+Jo*(-@2#b`}Uo$n_k&x z(9(RRVMU^xgjJU_l2fwH zkbouSl~t~)GN;26YcdT~Zv9lmE)B9#3CXdJ8Co<1xkjSeSy`r4Rk~*MmqK`mX?UzD zE-r3Z{9qEou$qRj^?zbqIF%ULwlOO>#C~1X_+x|a-SUrLZmoOpk`~e??>@c!oxK}xDJuB%^H)E+y#0ZtyF0JH`TF+f)b6SNc;mlreDjOr-#oXa|34oX zH{;*)YNu_={Ptse%Hf}Oy}IM!;y-4;9QW#+Gmoy?Fl_Ib&7T(!e(1}7Wf9;0bJRBj zI_AIjsQbbN6}{iuf23E?6&qf8;N|a!4?8}luFD~-xw_dj#>v1Nl(Wi#y2DYR>7%Tk7hX-JuHQ&>5f8~mq_nbQ@@}qP9_3sJe?kaofqeo(9uf2ZUhu?g;ZuaIE z7mavfdbfMFB|k7Q)Kfa!vE$w0QCm07{k`3@kIos;PA*F(^lPYap= zK@;0t(8NwM{eLV&PbIKcJlk&g;JqO$Z+|mn_!DOiSYbN0di9mpF3azKeYmOL;d^Xv ztXneer_DQRAMBGBVtH`-^0Uu*D(K=#A$Q-p?(Tx$r_DMXI`_PZ1u1O`$KCh)4+9?? z7#zI)z|yhrJ-Kvp*1zgj{Pyy`^*5bWT{QFFw3$uopM6QB-FkDSrRt6OUk?7~IZM2c zUEKA%>t-da%zt6Rubn%LFSABH_|kxPC-<(%`r`cCmao4z>g}hV``6Nmp0q#0u1WlQ z+~x0CFMYg&E9A-}QGZw7k+$YGO27Rmc=1K&Z4SBEUGm`irCRQg4R5Y|{DFj!D|=q@ z?B)IT72gtC{YF{Qx_w*E|Mv0?cYc58d-wd*?H_NMf8AXAQpKQvwR!sxgsqC1^cGwIb{ z4WR?R?eb&SZ`)7Xa)o`$TgOIz+NSWKua56pJ|ymuZdtp|o1S_9;jNZCFMDRu6JLDZ z*uU4ni0wxvZU16t+-7sii_>m7drH+;6+6bg`{+l#Qz!Slq9$U*@h5v&yU^0i>F;z2 zoGyXWC2+a~PM5&x5;$D~r%T}f(-Jt<{?BRm(Zyh7`kw;i=XCu4 zgXMp0=7#0_+HP3>Y3B{g_n*CC`4>GmEI-h1!}6~OZCHMA*oNibjoz^QQ2K`DhjTY9 zKQeK{@}I36mLDzKu>7~G4a<+!Zdm?du~=FaB$ghVxvBBHkn>ku5A(Hv`Ta#Nn>9xdC{__K9W z`jfIcHY#uukEJBjUm=| zMSj9A5mkDNI5ueq+2ck1J8MEk;WNRBzup(z^&6WI1rFG0ELa^ZekC3nN1{L*0=R8~ zI9eYzyK!Gg)C!6_IAV5VXw>Y+uZf!b>WlilM`IrT zBeT{`#%D%+y^yBSNYfOgDJU{w7mk5O1w~#e-7kmx%%-Fr*LK$3yRo}U?|mp6DxX~N zeg8+&j;4-^ujh5)lCS4=op$Lwlt0}}?tXJCJT-nE^7~ixmE$2BmQ#G17``hcJly@6 zHTj~AA)=tYsLxMoGp0jOpUvm?3KwUN4j0oN3nu!xGG9U9?+toVq&Q>$we|V)BFt0f zM{b<-Wz$XhU&foKd=(OU(a2sepF1|F`$d0fo6nsZ)Z?PD)5CZ5ZzHCSK^yooR80H& zcvHcccH)d{Mf<5Mk2T3SDSSQu$3r$X{?-2Yca+UuluvK8AKg(nsm-C3@e`D;!|zeM5mE&6mOaca$x~N9}L65QV)&;;))e@@#vRk|pH+ z|D;`A^PjaVO7nimwa-I>R*V+nhd0o!adPd(UZLXc3&bV6K1)tsQ4*1Om}E7{FY5Pm zfRnVB?n(xa5EtCgi{P3LyY9OLd1Nd^@Qpo1&^Jl&_j^;**_401PX3O5y5n!Ex4+sa zjAi!^$O^sezCd~Y+4ActLcd8wIZ@eBS&kNA-xR@4WlH7U3$j837|ZlnK$-p>ZTN33 zi~qJAUDaWi2Ke8eSG_H_M>`~W)6*~x{corXJ$;`Z_seIJgB@Yl<=~kHxBrcK_#JXd z&j;xmy^daUOHkzbyGZ{~=59Wj5{$h3{zuatKLGZHoVP-(OT0yB=kF5GVLq|`^iI&t zA0PfCbNS)f^$QONJ%BJC=(fuy8s6z0LSsYl3Nv`k;N1&3^$Fso@}TlUJA`@qQzXy* zwBo0H^iU(+=BI}n=%EJw2=S|)CklT#(o6C83I||3eH?b({qJZ;&2+aQQ7~KP*ZEX0 zvGFkF_r$X4whOoSqZD5Qc+PKuN9lEcRbJ@%G^X)&$UUkv-HmiW+(C+>y7bfhy5QeY zMn;{R^jo1R{Z?p7zcr@s2Dk@>HN0bv?6ynl=BDnxbp0LUnx02$8@;)0ME}ig;_s@r z-;Vipt0tKBwErD-qKAdPcr)fkzCJ@`th)t4&w|c!vu^*p%YQTSME!E>-<-F6*V|t03&5WnE5pUm!HglA9guReyH|cc+9eC;AoFBdXJEP5Z zrn(xT=6h5hmZYrM7%jEZE|e+7;quxN3@kRHwYe_S3LcYJSq$X>A28Yj6YNglVrt|YDj_J-4N1nT?OmjKC4$g}TM+gzl z@5ZR-Qa}j!@?sW93cptq;ED%t_??>~-K9QCnQ*xhpUkY??zTFSOFj7kM3u`ycE|KV z&XVGi(y~FtxPPF$me-=3N?cVXQ=5fgq$uyz6;=d*oHpYNr22W?&gqWksUlt@Rq;;u zI4V8O18qj~hp1w&MnSu66%{Q6-U@>X!B-|8hu2zdLl7RlxboZ%Yf4JK)tG5je=WJ3 zB)Arw?2b}fjVmz5W{C-8F@#cUb9$|4{Z^`BuiJ)7t}N4&EdyzVLxo|^OUY}o@tSj6 zrjN6vrc#5}lB+69on(Q(AhSifIVr1UdR`s`LW@py#jX;Wv}UbP zmV~0CH3#yjvhXJYJ=Z;h`VQt#_+G<{QLh934Zy=q^hbV)5oDJ3qkV!lc2e(}krQq> z`@XGAH-qs;a$}dbn4SUpO$PeAOwR)S76bhwrssfuyMg{0({n+;!$AL<>3N`ILD3iQ z4@@5i`mF}~QKsjEewTsX#B>Yj4;$!VomGAdKwoR1cVhZ@&=(u%XEFV9(4iFj($k&k z*ek;eaeg|C%|3qBOXPw|Wl44*F%CdwNOr2P0sxf}*+T#m0F-vJ(+h6n0aPYrr~B!J z07?_t=^e0%0Ls(&oUu8%6LW+mB|9O0h(v=;K*8A40b5 zgdx%!?pjGl3T0ffWvEF72A;q5EBMsk{{G8=K!{FFKgpnWisWTG>hx!n5M{@5-9kU&g+mWNsUFY-R2%kv^ zX_kN5DKh>lgMrCsH0nlBB1I_u5$zNie~s=wPttIv!FmRn<)3znjKBC#>Qqz|D^&(| z-Pp{XAFtEhTExZ@K;Z}~A*5E3|7r;hxLDIPQ=zF&L|4|hT>XV9Hg0hIkfFm8hMSX; zQ&Q8$r&)v}J3Co;s!2T-l{V_ws)tny9?)2D-UAVK4TlyYHNsZf~kv^y? z_0H3`M2z>4Vrzra;qZ90zSY81*VhzRsEJg!8ya_Qxzpv)N~)@7Xm*>|rg^Khsv2)~ zjaMtKDJ^xlH7MbIJ))r8p;cE+b!Z;vRSwW7ZkNqn1_p0AZvWd{uBuuj1KiVXt{TVC zc)`k@a64?2=xR}I^OlqgHMAq40?HeumD2C=R=J_KOO;aK6#|b#R3kjMD0R9kYHe;u zt((;GGKZHrot33kqS#ScQeI(mPZf@eiV{&%>H&XUS+!T-fddz18%eXfkVd*Ai(I6n zPRPqo*UD=((y+Bs8}d$RZZDFYl{WVbT4D5EZ}RdPMPNR-&Mtc3;g_m1;TTv$C2;4Sn3s71@hil5Lg! zsBx53*&UkA>vcPeYrLpWk5=pSmTR)=D9`znWHdCb0{X7A8Z88k3w5NbU$K?Ct17hd zmL!BLT`3dI@(mRn7nM~@L__47v(nT~cwCsYRF}{2I7@6UQsKQ$dTGL1SyNGrYR|-k zjM^5*Bx{e##amUSl{?GIDNdOk7u9a|cuRqX<~H3)xvC^zC>V!q-_=!4n%q$-x*gsc zcO}!|J2x*ihg*m$I;y$KD#Z|^)jFK+fSRnTc2shPVl*{H#l(a1Lep8zRYS8}<)0?6 zm~Iy2=F9gWtazm%>9T@Ui*Rziwd9B-dQjk$H57!QSXAkIe4bl$HTd?>4B4uD`8*kk z2Hu?U+18Xy%UG*Qk;T`tWUEB8LIEPTD0$i8spv1I6zUC7uOpHG)LsL_qxKZY>(;8# z-K{bP>YM1;h^Dm47%p*m(DdC}F->V>6w(Dyj6Vcn_Dpry1LGZlbV4*CTn|Y!548>I zr(Q@L7dL0>Xo5PfUR0i`&T4D1&2E)ZlDx5c&^R5!QBq>nWv!uWLxjmdGjp}7YHGl$ z>mq6d?3VzPJ#PLgo3iiZm~&Ey&)Bsve{@zNGY|$OF{1m{^oNWmLF}l6z@jdvI#ja` zNo*ot^G6ua^`zwWi60b*-BIm!lt9ec(J@OQ1uJb84neIzkPNa`m6jrFN@A-LH`c!r z@gg}td2n2`@VkJ3Y|4d{zUUXoS`LOH8+A>pMshB#sVtFC%Fr^9&5PLerlANlj)5;a z$(#~X*dL*x9qU;|J33W(XluPjk$+DNhEqN0<`Fkf0kuv;xm8tQ=yS-VA|+*5_mJZ% zL?6{GWht-qV$OC{RJmv5P*GacfF^|m(vMbB<(IBl5i5ph6xp`AJlhNx)~YO!ods0| zG@yDjE9GjH$T5!{p`DZk0i#hA&(O-NF!msM#u3?5Q(ax$M6X~3p1e8X^!r`QTH zUtHswik{}RUgfH`R$vH6kl(UkTFD-g;3MQPq_WbN9YxHDe8KpPD${L?Tarrxi)W@WllkOPh$enyUT2BOu5EbpMvO4T8AuR$z zMQL?|q@5)u={cIG+EL;xb<&C~ub@$V*=fwCHi77{@MD{iS!sdlQfc>yiB6XbES?&N zVu5x9brGdis`Z5iSA%R4UySA~MamHtG{G{DhB7UI-du{-4PDfZWnMTz_>l@Niapg< z$Qu&+GTP|=6tRIS<3JS3A+uDQQB|X%t)oyKQd6UdDxhZ560{s^WN0W>JE>hV(1F@S zJ!(&RRSnWw?9fv{(IJCAJCgkfbzv zEQt4)rLM+vM`cwFG%86&Kxhawa60@EI%!E=l{ji7Fda1UU|~mU95q-utRp_-3xpfI9UVTU3h8Vj}ykcJ$ot@<2i zUO26$%6o~f=#oOCC?hm>lFEltEjVm9K- zht+A<-CeF4Jx;u{hOCg{-GXCjtraW(w0*;l3iaj0$0#c{W~5esG9Ksvb}MNaEizqw zbwF#N2I#iYJPk^r-k$P}guZC<%?3R3B3m@|3*X#TABbf@{uURYAVF!dxjZD&HD#3j zgQpazgBmGN(JBitXsV$z&*7FTOJ#{eQssaXNThj`k>;DRwk|l;TW}B-G+DvuZPRMq zRp>SuW=jUE5F`#Lx2PHjO{j6GAE?84u+Lp79CeVTa@aS;(M*s|j1z9h0Maz2#;aS4zhVmHtHdtm_tr?WF{wPIi@>Yq81|7S!H*YOk=9tikwWb zAp&nzy1S}Y42b>H#Vi*ZQ}Qz>q{jQ!b;c$MNf~kiW#|c%VMa=7PKLA!X(%w~7g){M zyB6trc~&B&Wtr1O8B%DKYZSg!G65A_ps|T`^na+3q+H6SDbhR~R<-B}`IX+vD5J58 zZ*<4Psgxn3m2_F-^@W zS5(;u80t4x)@QJPnxi4jSxIIs4s$9w0VJ+0TJ$C=WraeUfh4$XGe{!o(-96ZSx&uD zB@aiWd{|4WYOsufG|>9148-axw&@A+7riWJii|^4@u^v^B4eCGLR8I^I+3&*xjUj6 zf-Che+|%fS%>vFML@aeR=ux~DZS*Dc>38wPHUpDPBw02?8h!Po`D2k`Quj3ktX8Ix zVMDrF%%&{X5;uA>%33ub4CAsKR72`D`otL3SV}&)v9%PPKY@zf<|5^h=9Q=LXiTR{ ziJ?YL9;#}J0jZ(%(|5b6ZEcLL(|6C0Yj@{4TPoV#bYx2PkcUgYdhj;;y>Saa?DWvu zJu}Y#YS+Gn@4s`$#aYj^dvVs2*R&n5_RE`lY*=ECe7477ZPk>FY0v%mv3dQxt9O2I z?l=2Csu;Is=aEawi8xz3&PuDH+xIx1TzO|6{9G zdC8TL&aD0BqFwH3We>c)KV)S3&d{-c%iF)S%SOHZ*h5Y`El*Fl^S0;T>iqDF zYwukf938%}jrFPbBVOtARfi|9n^iUFjI8p)$9mW{jT%t;%o6jS>0#483|gnXv+SbC zUEg0n|H)}R*E|#U@cs?=4c@u-zyq(ft&9IvbY9%p?)GlWI(_m&$0^qi7*!E|hs%C* z(BzUYj*Oc+wb-abob}_Z9g7@UJAW^wEnqJsxet7Sg_io!gs$$FA z5B+}R-5pcDawZ>pzcM~;VcFx`*A{)?84#NCd5@66)~xm`UYphNqmk3v0m%a9W|K7{CuUg&s-m7Pidit{29aj&$ zWb%v8KJI#cqc(T#x6eGi;jV~Jp9#6^ohQA+(|3LSuiAJ1dDev=hR*G}$8%l|Jl^;)_zZj_D|m1_Ue>dJ0E)I!SL(K4+oupd~=xdiiyR) z{JYFiKW(V%oG-(sR!%=}=ka|P@3?-_RUbrd8}m_F)!yfR{q_6xi<8$sd-krytBMXh z`0l&c-1_$YTQ=`b$UnR{_lL3<-Y%QC?vane){GuI^r?&wF7CKH>%8{=`gu&q(4wnC z%`bglw0Hd8vc~ThSH{j*?@U|twC&&L&MjTn@J?0Vp`VuL-&Py3EhN3e3(s{8?mg(j zHsjY{^8Cxu9bSCumPxBG4xRG!)n@zM7alG-c+Z1V zYTDmg5xhLC-94j+cKT+1SzC9PiK5M%F&l1+x@zsGPh9-u%!KoviMV_5JGXRPzw7g7 zzuz;f*WM31?0jd(f}~G({&4i^kIF0Oe$excuIp!Ce&KUJe^R@usy6-EZeL6aUsye* zbJOdWgq2S25OhYs%ed>`{5T~ zykYb6ubXat+VaSQtNXMWy8ZcE!`^$N|HO|AHk7@8!N99ZpI$r0wk7zy@++2JTy@c~ z^&M8WUN5h}bTj5AV|eJ$gAhAX>YmMKkz)F)cHgJh;XJ;HvO4>{!~N@xqDy68Kgeg?VZP7?_l)=4<>;+Kqz;%G5UL)89E z$z;iSp_~!Y)+BFL`lD;MUzsd7Y>_OvGsTk^mg$sk8ZbF{tgoUFkUk_xX$??=^u0?t z)A&=I%@&bQ3{#}ZT_O&uuSaMtE`cL$=~xBLq_rYWA4sj$mYM>PHf1PI;iu|3R4t&@ zVA3XPYOc{N7(canFshV%OP{{v(vp^i3ecZ!awBp;cF?Z-aC_duIE&l!5ylPNt`pcj zZ=`DHMeM#VUD?+$Un28uXTEag8=0Z_wlH4?^K~Dk=+(?u&V1XLFHcVw^VKomBIeu4 ze1*(c&3yIDw~G1pFkcb#^|@5VyO8;gG2edXD`&n8=3Byi4VlW{LFTJwzWULMzD!Tw z7-c`ge09t>(yZtW%;(Bc_G8Rf&wSO%ir&b4rd(wYW%q@Q4=~><=6i_wBG{d#r5f+s zVI#p-=d8ev4f-SZT&z5iUN4se)O?TIs8L3E>?I}tjgY``$z+WKYEk+rhAK=ewcV`LkSZDaBNF zhJO{wuE|PbArJ3L_&1kY&BFAHHa%pj7DLIEs;L#Zo*<8PFJM=v%Jor0&Mf`MjL_J5 z7+?mf8kVz$@F~B|671)a(WhWP4hOtAH?~qb0TjSuEUuOqWDz&dV6)&1IpXwrd<8vF z%f%)d@0`%qQ6V;89ktCU&C`zse40i!Pa`Ek))E!8+`w>ST#yArhc4t&F?iI{Fr5?B zQtP}31`;CKlA`5f*r#94tZZ6Mk|E)yB(x%>+n`=@nYCVPpnrJB`l}NynS$_@Z zDNicmxPq}1AbpbVbSf{>Jy6oMC=^@dY*8k*$Qd9KiHEf#l|i|trv#mGuS-e-G#~w> zB}q&asFgBEqDz|yk5(Lv?5_(&^5K(ivLjTm`G@BAE6qjI$R}Lg-7Wx@ObbhJ%YBkh(bqRq^aPqK)g*8w|T?zI(RGVlWv^!6$|5T~XBE|U`wNWpXT!TlY`1^P34Nhh?`Jp|{ z@zf5eb`8$?dD%%2Z8p1_WhhreK2_Ff^fv~CvjnnM3h0PNv)ng3PY@WHaj!$8{Rcxr zvc{`TIF0vI3{JA#s2->^4QW%GE-eJ4Dn}NFeh`7G)W7s?@M&bQr|QidTh}=;`m*PqRSV#@c))M$|eZBP!fpQ{p`-k2)d3jj^?W zavc?!DXm45Svjr7i3Rm!K2x46kLAmA>9RvNACe0&R!M<`9yitLs?w*Lv=Z+>p@}}l z$G7tJ^9AxusXR$AgEH&eYZzp!!T49{)z23|3`2W%mNw_o2Mu|A94se%LqQ?!LK71* z^9-l0Vz6GIp9rFHmg2?8q1K2=3sf>)_=jZ0@8gu4==$ykX-eki>6Kx~FePWHe%4?3 z1q7vt9ObSJojhgTL8U?_SVe&0&}(zza4&XTX?Fn&I2h8DS32i9sIPq#QeaFgrbU#k zO6-fO{eC^Eq{5U;#fS_K8FUZ;2_@Z7x!a*i&~~0YqaZ`@o#&9*fTvXbfQKYVeGI21 z3E$TM+Pz97%-p&!z+%P$m66qR)@fADzW#dmo4YZhB-*JI*e+_zrI8x546ef=n5<~ zLsCLOmAgR3Vx=a7-Ewj{u^1)!Pm~~~P4dcSFDKMgE>x%fKzYkYRuwlrXiM0B@hO;; zP6`U%P_%RtBEJwj^RB7>BKNmCc4h+F8cxSx`v;l9e^5r2B91cO}L(4X{ zV3`W7uEM1&*_dprQ{j|gk&}zV=ne;>r3*G5SzlnrQ5YQLK&o*xlft)YGS#Dnyqc0U zJ}oUZf3$uM(J5QH@eraIDWD9E>P>U<-fZ;r7Utx!bQ)TW#1f-Cm&-?DdyC$5NQ_Pr zkLoQjad-3Ek)ssNS&yO}(Kc;vx*vIjZ;gg0uk% zy|vMowjW6?G?0|(hK8JwZfD;?+!aur|JSFc_oH7kEW zYE~>%jM$;BIxX7oFUyJZZuyQf?5R84{k4nolIb`A=0hUY(wZO3j7mH1t2q4rM4?IJ zz+<$+SluiN<8&j)gLShgjMt4I57Et{aHwtsd6;e%g$cS5H z%w~||4dfwy@=ybLn4g?rAP@JE;|x*8`J;?8L>cFgGR_cXoIlDqLzHp;DB}!K;wqx5 zDp5FCkCG2vL#|;wLnX>JQVsP-)*6wNn_HmzuH36a%a<1<(S-~1#%mLtRXDFnGq2nd zI(UVPk@S_H;E>unRKxahqN&%!|;%kA}o2CI6G76zb*AXz=7G`OL5 z{FY|Vft)~AFMt@x>dHp*5U@gHb(VrAze9Pd+_FMd&WxVv!4%MGlGTt75*Rp*JV?%oN@S3Mbr*a8D6ObPL=Ws&d zuAAxdJ3S(x+X<6*dY8jUBQw3VL2qu5c4BlR=@0^-=0g7HAp*MiFVoArBrbcktENm( zZUw#MB%Lv(!ud?y<{$cXigLG-0;aT-6I+FWc%}&muM`%jLA|*}EXywCI zv^7z!zfc6VSzQ9)`$aD93zT1y2c1IbhV`{zBPV4*7EhVq=j7cU=Z&~pU5)n~SEEo|KKC0IOz_oxOjN=&( zV@%WZV*t`a2`}x5hew4N{jS12-vv$o=)s2eV!Jph>ct_6moVNAECjiC2qO25(taHF z-wri3b=H~&1rd$}ZfZKzByQUHqfXyP_CwnbfLDFT#mC|&@gzdocU@C``gKhrog64t z)ZQX)2o=>^&Jo>jX(O@t8m)9=R}o%HEj3asWSqfxE92HK-R(sK+!GEf92$pKjc|i+=pgyR4l5j#LoGd0bn6-_&P)pxo%0lkJiKx9 zk5G|c94;1$vrcfYFA5doBGL2K1q;_<^r-C!=0G=L-xw|~Kv>ZiqL-d8M1Eel=m)#V zi1#DZGJf3(+L&j>p_SAc5w(d5#|gbtnh2J=TcaYDF0W&|B^h! zUv!3#Cpsfkl%RK0d@I3A=@1vHaLy%jv`UX|wiSho2GFBtscDNj*J2UV?e>y7`dcCY z+N_RZCt0noYNu7vq){>1thFv%C9+Q6w;zA|aaK}JYC(R1#gclN$hM^Co3l;Ik^g39 znejZ3NxdtAB+;k%l$rigyHI?wC*>nqrTF4b%15$I@eMvHA0O#$$iB);-q{u9w@#`PRd7)if`me`RMHx z#W(7teDpet;=A;ud?ct8A6~qtkK0vpZb~W|pd{&k6rUX8gs4{v677?=%-4ys4nFx; zY&@dI`<;x#e^T~kY}fI^parr+g&$Y$F^p3fPi9=lcq!vmjJGj9$T*@&h2vtpow0g2 z5W@uCP?6tel^^;`ZC;SQzFH)b+3+QHQ|T*W+`xDhW1ThVg4D9>AA95b<9nW8HoYJ& zvh0g?Q|3QW_JaGz%8?^}%6<6S{7&N*mAAS3vG?cpJm-ylm)|*K&Lkt;|IPcAM%c6N zyqk>h?xy0`jj(Lc4M{hr44d}W?;F=V{Nb9fF5f(1_z!3NaM?q1M&GjQ%I=RXThVrR z(B*T_Tt7dy&r4TFjQ3u#-hKSZkLw=|+jF<~hr2gza^AgvLHhddU-{>z&fD&f=u;K* z)qoZAykqt(Up4uIg}+YEA9v}pidSMAxAqHJ_3E{kZTPXnzE{$3estHklGnq^`uC5T z-~QQt3BAr6c&s8OyGzFeOM$1o7jGNUBk}Ls?F%PX5Fgzrz5%#AG2b2PVVdXT>fL# z!1C|r+~ln)dAKgBZtJ}8;8z#@*0g@fH?F*getGcM^@r=Gy+Y+as04E*bqiX)2x;{? zpb5zP&T`UcElADIvnFSxCXclyS@J}IB{j#=++zAJS25noc-BnCw~+Bt#tn>D zGH&YJB$~FpwC$yl+nSCy9sj;*Z_`Ijzc>B9q3PPD+FxG$9;(Kn&d0Wm+%|aITTS0L zeb@9y(;s`AHZ;A^^h?t(*UtPHItJ8S(lxei0}p`yfb<;!{rQN1{=7gye`*P8n`&S9 zh}{2L0L$j8e6D63HBZ^MvV9L@*A0q3nX#R5T>uVrkH1Ozt7E)700+7+T&novZ)+Jx zFnt!|dzgPCyApAZcT@H%i(XHkFqGQsDA@ir+Qkwn`sQ|;ec>#$A5t1fgub_PyyVdCwH?l1DP zGn4sFd4|JQtz}~(uXdBM6mi0LM2Scr-Dr2lm8b(Fa!mz0Cw6*1$}XQzqp^q}@YCu4 zjT?>Ut@&%sjpEni3``4Utu;5&m0EM7v7$9M8cJJp!z`S)|ObIyc}a>f28? zdr7`Lygblhk*y=ZS6aHo;l=X111~nX4E{N4>70b-m1$3_a^uViVvyg`t*XClXMB)x z_-l&ZhjAj~$&6`{ZhT&hhD{a<7OfUn-Eg;R0<~e;vdk%#JZ$68foo;Y!+9_4{L1Mn z?p6vj5$LWEZVLLmU7~4YQVR;qS^>reJaCN5sC=fyVIMefpph}t7nLkPy7G)YK-$v5 zBsV9QE}r=!8=+asYt*AEDYWWF@4foj{d|aGpeorItliNHw4Y5nVU66E*5;vLGZK%G zVgGO-?&w$6VE=0dCdF6+OwPi)DJD~e`9!)RbMjdx;87Kv!KUV-*0ePBe3t{;;W4BAGlhJXKTiMo7zS^kj|GJIdm6*(z*Vs`^ zSZ-I>8Pd|RS9`35d(_HMv$k>%cNXBhOr`NywAEWWx71T`3X$V`JKq6R1 zL^~`hz=4-&bj~Y_3{Vmf1%rr0I4|zzvIP zk{=pstmLZ`BgW$O>xuc+95Es}DT__uiWMWUu@1F1U5rRcRye;PS&Xn`=Vgfz8Rq;H zYksOFwZIr?oE|9RNlQb*j1j?xr}_{N$B2Ce3Lz7e^t?FwgE&cbuue>Y!D7wG&4R&_ zo2KH>1N22=!9GFiU@;=Mz)}D-enM8R7*Rmn$w*#$YCe*N3r*QtJ{~b_o|XW*9;8N* zoyZ2q{Is*1n@ib=j)v7!3|s@$ogB#l`6t1A*8e zUiHm5)Fj%S>S1W#7TEz?W5`Ou-8ghmQbhKBt@Mqfj3d8cJ)Uu)ZvR%%U5x7(uRW;f zgQ_c>B{Y1}5gpIKVrQjPbHqc3lzY|>3Jb=%{V2P~|ESzYGEQNfN6oFkI>DSZ0{Rzz z+QC4;cDZ^=lil&O8}ER`rM0L{ET!uqKxKoZz%T|2Q31l;NJ19-qFR4U`)ydel zAS?OFL-R>1vtXOTic26eR8ZXe3H+)-Sq?%SdvT}JdUzQ)e*rGC!@3r6{o+Q${ zCA7OuDv)YOX#O(be0n%d(+0*3Gz~DB1`mxNz`;*S!izA5FX3nPyDcLb z<1B*%S2iS9{>o062S<)vVSfx3fY!sQ#h1CeLLJKQ*r=R`+p!9}0yu$xG+ zr0J*DKw9ITLsY-MF; zC&l2>DTuMnh{AVlL&ktZ8CMCM=0Mw^BfGxmTJU5u%?r^5rK7y@;GwIFxTh!2t{EKj z@iL=)WYw--VP_3eo7u2ug`VHM-C?YjamQaF9NmVb0R%z)2Dv5z+mqbYU!M zo#Ud5RP$8NY~U4MdU{PB!=;XkUI3AZrc38zDR??VS&d}|b-wkYiv;cRs(n}-p|e#x zvG+QtuPMIJ%70=Dt@e^)IcT~u;Z$b;tt1NsEq3H#h)TIch?^HO2{RiTatD;&Z018naWVAtt7?!)ed%awl<;}phqj2AI(V7$MP z({&2Gx)uJdtx$}mr|X3<@*_Ug|JG044UsaV8o}#7jUPbmrwygkEy7t{4)V5&K3fa z54Y0;>mF@VR-TYn7cPY;E6w@TE8YTU!EkV`66dvX2n^Z?-g!*L4=v#0j=bDYPxmM1 z=H%c9CxjC(LEEj>=-e?csrp#QcqHRJ0r&vhBep31K=(gupU2^B*{Z@>`I^G38Se?O z>-1A$@wy5pk@2=yl|Ay`3Lj;9N`O6Tn{r>s^ajQ&8SiIIhZhr3UbJ^cSU(3Mb}0WN zcPac(fZe;3!)LsOaqo~=>|YKR@i=Zb6uX!SVz@8~vq%!jB1NQPKQkjUJwv47=UPNo z?nG%A5T76{{aI!{{5coyS&#tRv5Yr9bDhX)uRV;mW-=zSQ|eQ$N#8)u=h zDpV(eLV_}B{Rne|@u|sqW}h)7%V)$|ExQ-^Oexu^%AB8?Zp|}Wp)yv{|)`+>K zFCy^_5ef(g7{7=j&;j89<99S&wUdz<&2c!}BN=yNtTB#eoWS_d809~7tiq9uHO3~! ziH!3Y7coA-_z2_BEDq)F090Iz2ILdHuNuVTE6aU)|>wn|_30G!D7 zJjO+gs~OibUd9;RFgUDjo6v}kojbMf(2m4Uv-YOW^!ShBV4qqo!I}n5hxvq~IzIQ< zL8WEHP=<$UrqxtWA8f64+p0}?vDz^2g@FT#jM1}MrV=ZLJgNRxp$F)oz+%h@7W%7`g$wONv4{L#p%(j$nkXuSO z$StKC7M;b~7dGMNu7)M)udAWEcIWIpm+hD~HS2a5t zVok$lO@_d(pgi>^+~;9PIpdihaRmO-wxXv`1Y&|Dho4~a15K9N0;HpHOd@7?NYgoy zks|V1**y*ZNBe?0!4QJu_CcbZMfs;OP5!bWh7&rqtG>>RDSn;S64uA5hH^EJ)5lbO zY+4mSr}M+~ZDhL6C&&ST1xXwPBV5c<>_~p0^;YL#O&3bM`=3e=ktxUcrpKEIZp~C5 zG#2q?<2F%ZsKtBRJcASgek)Y(g2BsIoxYtK4rMz*%tI!Fpl-ff2;Ha zo=6YU?=%JQ2M2TE1kgi5xDf=KtaExU(br`)-Th@NwleJ;Y&KXN0WFaqU<&eM20JyABL+K_!%>5sn#D1;QILt$By;UA~q&SEt2mtGeU!vk6_g2G! zZwiNaTFv{$w!ZRdH7>L$J)G9d*&kP{<%4w4r_P@%bKu`lZE^UbUW>zHfad|P22Sj~ zI6MWA2hae^Ko6N!-~OD`{vqMf$bbFf@KAz#7KdjnSsY#uhzBIxyf}O$@FKuunC)Z- ztb%#s1pa@V7s0Qo->;@bK906p2zXA9jz%sxRKmlk=fe!%^0g-_201XfY=mzKm zhz6LJE)L%b*bUeNI0`rh2)%7_cm%)>*a*968TbIZ0eb*P0mlHLcY+UK2W*7B=$6Id z4*?bdG5{%nqT4|OECOTzQUF^~7TW;Z0XqR(0QG=*fQ0}%ARh6?Bh20ZL>#b30-^xj z0Nnu^pbsD#5Cbp);sFVOk$^-%3LpcJ1;_(L+>3AklVNTEECN&myns5uEWld8D!@9x zN`SEqKyzyw6>bU+?;2D;=drJY!@3R?qk~>+FXGQ40n$Dw7OixC+YX&`y4BW)bZryj zH$|S=wOyF}Gq>FXiNSC8Oh2!tX4`%DJ)7g0dR9mIuLu3@RTLbW@?}V(s9DfO3Z+mJ z(iw|90?z|p4V)Nc08xN$fIfg|z{b^x zdkyLecqd>tU=QFZ;20njZV`ZZm{S1ZfGB_ft>`JVBfug+1|S8n75Ur-*bdkU*aENv zA^?$qC_pzrcYp@y1BeF108D^*KmuSSAQ6xP$N*#k@&J}dcZuuLO?aZ3#bFk z0_=Vc9Xtbb_FW(1 zJ6I8k-(7}nu#+xF?nK9(wR$6eDQJ{N3cDOYIwqN&0Gbbyc`AVPSTcJ7G}x250zmUQ zGSg98n#+;78bI?nGP?mZr6)68)1+wznIUK8{VOuh1JHDx%+~^FicaQR0W?P=b39`* z4+hZmo6J1`R8C~h2GIPF%)J0KHze~Cz}ak`58RE-(}3x2AMwz7&be$(1wN0>LxH=q zIUShdBmOi1-3cUfG5~cZ%_+bdn=^qa9mJCX=*{N2z!$K20dOBSUkBWm%?p7qWHZE+ z=*Q+8fTP)bBXEBZYUg9G&wL=<%$xLl?IGd>*j$kvj(M#A& z^+@+DiJ$6m6q_~ROW90qbu^o)d=lAA?bgg@iZhAL6eraig-LCg>W$3QhN=F^Ol_Fz znatFNss72_5kU1x=1u^rXEIY=jA1ji=do<2Hk`#~;>%_;wPC6gqEQ>pWiz$mJT_B$ z$FVsPIG@dwCkvY?-vw-@G8@lkDzgb}rZStzW-7BnHd9}?jLp=3Cb607|8h1{olIu) zO~6+Gs151u2<2FRCDS;6^;U!32KOS^$;}Bf?7lXL{#ajZurG$a#9&_ryPfU9z>mTn z1We{t2J=RkLqOBh^cw6AwiE9z*r^uDyqEn^dcK9Z6qx9Lz+6TKmX#4fxV8%`)lGMp zsSS|1AI#<8Bi1;WDLs0;NwAl}N@3>{ADeA3Bkz(v4dy8@>wXYG{Zw{a3bTvNkHTER z<`-bDgqi%r@w(CAbK;}cQKxC;8_9g};M;Z*zBJ~WGy2)P_MC)o9P`Zs-@%jc9jH_5 zQIsHtO5#9{ouT+{dvn*_;nY!E`8rNke5O8ceVf;=6(*3kT(0;Q-*@PxyHOKp7*L$;8o`i26^W8h`=7e=8 z;d`o`%I`~-+2i@aOWNe*G@N)E`hPjhBmzPrm{izh0+zVZN$WL5j!YZ-50yq)nL#s?T5VJwQ2zX-ln{tyoB*RjAdf+hmuY}W0w9=ccR=F>4~?hay!K9!woyy34;3Y zcA{uhxJY#4ttbYf>${#5CeJ^~C?>mAK6PBp_Ik!^882bnz_`zEQ%Ky&bPJOZiR-=TDz|pKPkG^Aa}t*Xx+*iE~xGklFaHo7Xa3 z=TBkxEXD|5?I77omIz*Ye5r7Z!_{zf4R7EhK54IOA6fZpHO4%yNG zMXVZ1V^PIXaF<<3z%+Kd8Td}X{eb0wCjrj^HUa3H z11N3*-0XG>@Lhlh04o4b0iFkJ2GEyhfKr%Ary>2t%k-td_W&LOtOTqEtOINTEC5^w zSP$3$u;cyfYG);WKX9rjx>uER5a{$Z+^*z{P8auayJ2i%oWMAdaR%c;#zla3NN|dHK*YDxR%RD!lV4g=1DLJd1JpDrKJ+VAtu30_fGx zD*ja*-o`b`zKyZqcoP{LR#uJjpTQpjt>?Ncz z3&r87p(}lOLQ>!c6MhTcT8pF`B?^24qOnSV4-kzkN4UqQ;)$c+gk`k&3t;Fkg(NSjjuCSGq<7KIVaKqg%2WpFc zW85DE``P56)SMwMrb9 zrdex}Xdjvtih1OJ0ewAI3oaL%5(-;i7WOS1Besz{RQ{jNagZCq}i!UaL(xMa8Fw14QgzoUd#P1Ew$dGSo*62SMDyAWdI4hnQpB`)V)>Jy^C56GUesa0TTPG^3@K#M}nWNHLJfj+y zPeoo9-hQVMLKlcW0>naVi5@WE&+ZYl90EPGFUwS=8Sjy_m^fmi1jYp>P!U>9pb8#| zH0)~_cPD65gLWniiDS-Yl}%!%Ri6L2)|R$Xm&rFt?>>-nd5SR?el3@|TmbfuV zM1g=nh}CLs0@#WMl|bzk5edWv3@8t#(t<4kTFX2LqM*&(+6#yaiVG=*L%!~RN3-RT0= zb#alMd0F%cjMq3r=?zw=+jjf-t}T^)I`LS$?1`SPOvd!5D&NmMs`|8589S|NSN&|I zH%9i#mih;Wsp{DlPwpnxa&LquH-C;x|3#E1SL*yS&Xe0fz59B2a(z*%TFM?`J({Pc z$ThHHexo%ZyQ!bj>#a`X{d`ru2a~@(($m#oO)`GqS$@CG_ax@$t^9fCB<5DA*$-?5 z))yB|^qwwYZj}~Y*7SG;?fI5ZM||(jGgE>2B8&H8rP9w>HTUueHNAuRJMErwf28W# zWKqQ)`c?He=t-G1MI%+k{49=N5GQ9`)wRc>b~RX&jYihkWOcalMXK!?s)yaGM%6QC z;6?)xB^GPu_bd$k*$4vmzvvGcde=@+C<+<8+TafVPddO1Lax4 zI*ryOcV_UttX2A$RiqLp@m_nrqDcDj1mAb3C&9u=W7C=EK@A0cC=P)A_o07gk}8+|M0dB&>TEBdG&E7)paUhWIfi15T2U|CPy z5Zun*v2TmO?dmlRyn0Rc%WLvmt#uuRs_V?uDDWHYy|~Y!Z}Izg_y?;l+s6L7-yiOM zwcWqtl&18k{(0UVf9p7C8|v{Uui8{(47|~M+?tks!kUu3<=Pv(&DK8IC#{oS@A$&% zZCUJDb9|ucO0bO5n`bCr;uDh&owz>2+cHpjD=R9B+M`vM&`EPI<$J+a!Oh;#UcAM7 zvX_D;Jze+4db<7?rgokG%)eG;!XK%dsvW?-iSlZm8=92PrcZTg zm>NBdKA@K!4SOq!KI}$MA$l1Sd_OBroBkB<^Zpi~ry3QY$DzUZOW&v{@^)*V8Kk$3 zuX}XpGyA8ECwP6EIc&7#>B}rNMa7iamBW2Mb9&31v(otIgP008Ier7~VT=s{ECrnDwpj z?}N!z>8nP|m{-cHK|xsU{fz#)!7_w?x; zGh1ZbAkE{eKdrI{^BuD|s@I2%yDGdedP+mQZvgZ(KM(qX=43vN)`)D&4Qk{Z<|BNu z^xMFkR1p7rJgRyQvS7s=qiFe{4f9(jET11ozehBC*&e^Y_?m2Zjd@o$W}ufG#(U#b z^%(j+j6N25_ZrWy(C_cwo$OnPeA}~0>90^$N}oit<~KwpWhWyiMkDi!h0blNI?1kf zeMui_mE-i(*_v+YDYTYk)LT=H&LQ9x84`z1c_219GchH<4Z*kJ!e5CA&>5Z z*HW3+Ot+`&T;E>0(3{k4ru|*$j7H>|(C<_yebi;@$0(o1Z{31S{(GjL3EjzhoMUXh zrIhu}@N^XsFyu}?@Wstbq#Bmx|?3q606$AcezepNhcv0 zq+Q!x1|?t8i8ZWGQ_lk5Y-EwsEjSdLp_cD?=;3hS^72asUGF24>%%5`8>b;p!WbKx z7#SMdq9x8n9%$bM#tzAYJzb-Di8G0;$F7u(!Jg?AkU-}VR z-iVyeFHP0Y-}mm8wbv_$34^d}^c>b6(7{)>m3j+@i2e2N<-!AgYgpas1!9ZEqsy%N zKGtORnK?l3N1ug!9F)Na?qRH{fp5{N*McXr-meDe1=JbHJJHV*u%U+Vj+m-GSa7*d z!>&UgK`-w^i#x%?f)5Ai4V24#H_>-r>UC6gt(E8B^Xvg`A{#7wHWdjki7g{zEzJaW zF$47wFI`+T)q8q@$nG$cuS5368v3x^pr#8v_hB2Cs+uCTW$FCW@QK(Sk$D1-y{7C7 zwYjbPxD_v7F>b@yE5|KF$DE+P^zq?1=__F8?5BT$f#7o{vsm~{{>Bd!)GsJWg=^(Z~G0ZhrE}* z`)WzGYurE)rFSDO(vh+o?+svn0@SPEWy9+)t-_Of3=NZmB`GowB<=`u% zHv}J|H-x5^PQ^}+tC(LJ9HSYYS6ZIW?DD`*e~YX-f`=bdA|OppiPgA+K)_xPqH_? zpz1!8S4mhx`7)a-7TsaX{=Q6 zfglbx&Z;Qti{1+1Ib>VTTBap_L>*VKkBVR)A^TwC%!;Ck!9KeCGWfSUTxy8uQ8)LU zLIab);Y8%>1g{^vU2q$c{g(Qdi?#;)$eRr<#9XF@?!38spR=}|bzY)3coSMNpZ9BO zbWM_~JI4Es`$}rXc6b55nS72>BHJFjfbB}T{B8`w)62UMZOVLpR8}kqz(obuE&L`h z6+ch-P3U*yuPTa`0lUm#o$hm%dC0s?Jk1@VZyTYiKj-tG!Fe<0=s6+!WBwufTXF;Z z#e8e#lE zY7ZbE3;WyFPr`pGOZ51bXtr|xbSog!YHrlO)l_vmpPEW%XDR$v(@)iP@QlnmsCbX8 z)Gy=)cyx{#6L3Oa$^q=MFD@$ZG7odT-FapyG$l5V^c&)Jq2ZR)4e3jenXP=6YIe8i zGE+xXD%KM4>&$UWZ`AkF_5dG==hP4rs|T;2$}{V{JboVVR_6GAtEKK-Kh<^ij&Sf0 z0WC!W8%_TeGJou8{|*QAB=m9)Tvv>_g>}Vdlc?L}k5ay$e(GPFr)r8S#!S$$Rp;N% zv-kpHOBeB5y|n|IKPG!BzrR24U%MaJ*gl`?TMj(_%bb(S7MuMMe9^!C8}ieP(xfmU}KJ_`AXf@koNt?F;Yrcu7}z;P-cp+h!|Ogfywvq=xsk@ejb zq(f|iQMUM+qUE-g^X+>}YNND!YNN%!%)6&n{J|{E+GCRD=#fDA6zI%Kd6|~cBb;}y zYSC_6xW~7W=XNc|{jp~6ag8O`9cOX$cv{7|A66MX-dFMN9ekfw3GPJRms%3xTjHBZ zO1~GmzG=qRB1`cz^PS34mWRzmtkZ{oUoN($tO*_EKHW=Vb;twcnb5evSM;RVu7v4_zI zZ{%hEs}cVDYk>bE7^enX@f2$oU%t)SBfAy8J+)hTm!Z?z&@DpOt?+GTU)og#+I5P& zh*YD7ee7R*5ZNA%Tpz$X!Xol~@8Q3W+@5oAfh8IIr5F`y;p=1O5@Ug%SI&>{If#Xc zo~auoYfVB9IovK__cHdA#PkLcJD7kxb&f~&=v`}tZkJ;7D$kChS?Irtz7_NH!YYca z^m7zH{cAqo@cEX{qfd9O9e}I|@w&t%#s1uwf2AzIH!@|xtn1YDD&FT61m2eh=^WeC zeD4}xQS>qI1G+KET@!qd4Q#&OdkeAKZtpWK0o~UZddma`oI=oVRkw822X$h19VB!i z^1d0KiVEsQ(Hl1OV9a8J*qY5fy}A0Z!4peyJ0k6phiHm`Pfe^uV_gTGkXd1ACd=q1pZ-b_M##mKd22LL$e!M4qqPL0XhXuzxt0MM3i1`I%*Y!HN z>!uASx+|pfun){NUh->^rP|$B+N#~xBWn>m{Qqyi;MQQBtM?18?(4>@`|1{_m$|8p zlT80@%Q);f_4Iu92Z*&~%&(8!kS_8pRBkurZAP{om~=09QXa)e_-*2Y89m&Z%8sH= z=3wl-0#!$hBfB|X`C8&Vz81fKG-alo#NXP5er>bO4Abqg#7KdeU8yd?-5gDHtIaLr zh>SdYhlZ|apD1Vtov~UC*&k}QTFlt6>=~8PW(GF+AU?zfcO9nh!?VKlZ{WK|bnKpp zd@uVS#!>viuhI7$k}z$S<;a!~qR`Qd|15YNl$>1ELY$5@bP3*%v%h5@p%zBJro5&- z0*#10bY^NkJ`#3G&@QTA-XWVg9~zPVLbh~hogAFdH&M^OPhkgN-qZPvx%!tVZ#DBh zjsCCb0c~L~EKTur?PV=1n8ymf8(GWD;2w{}Pq3YekC}UMN|!dzMyRe0ybt-H8tC#>h z^EPpJjJTr2F)M&u{{6jX)DBeD#~EiOG4?a)HCemhZWd!M<&(=8f*&d4of%h#E=-)+ zuto8McD>E#1K=QSv!IE-z<*G<#Vc)u9`*u{O?7PWOUbh#N{Z4UjCr{dV6@R|4)n!QA)SK*ZXIg>U&V_m2D z%=w}8P&419^nsi(;Ss~Pz(a5%xD{LNUE;fYhz~Y^SFuaQSHBbZ3S2^a10g(Yq(9q* z(nDK<{R*r?a1PNTGPs&l&GIbZQg2<69-_&s<%GdY7Q% zyZfmAeOlc)Y`wF0guxH^bc?XZD>YqsZ-4&y+&LUq>R{d*XuE8DAoi1-q(*;X(!0fb zE~^Ykv0b{3BKFw#wd}Ilw^TM7Kv_i&ZMUgE+T5e{Sa)ecZ5F>3f59MpH&C z30OM~nPYW?(p!=|T^lU+)<*PQ!)*9}q|%!Tl*BlUf*Ppy0@zo*ze zxx0I7<>=kwNwJ>Xk`bE8oAva!vGShI7wMw{yK+0f>m&2LZ$n#Wm`6Q$J|TP4$jB4$ zP93}>@cLAEh&8Sat}&U|!>hDyq}?p=bJAR2T&wVRJ^K+tH~oTjNpKkbFZzxI7GDY6 z;PINxs_seNOP|Z6UIZ|McUMGse1m!iVuFJfC(Hon#WH?Y@3bD{w6Jnl1n}Dg5A{%8 zs(taHdxK+i5UXoOHZ6xAk0EzjfPGcA(vMqvXOGjOT4mq9%^Gb)Kcza$M|*O!;6v*t zo}7Mt9^Dy6zCk#-2Tx@@x^wdl^LCcoRF5S#HNPTn#DM{pigovC)~W^-QPtO@^b!@_ z3WFN6F8Yg;kwroS$-uE4c-7^H=XTy4D0_r8iyV6dI^73t&Gv-rr8P>wRn|;g?wo0( z-vW(}M`mNI<1Y%Y{FrVL+7;b$7~0$qd_G9Wj=~RF!CKK1zHyqZ412mbdU3{#1JIG< z!HgNz;hkfXk%MC6iA|i&xFSbS1E+dZK0Dc?Pj){vK;&zRA!TB_&5SGPoJpD3ZyCWh z=&;crF>W(;RxNbS*q^StK8{en6xQd3M^8ug$xh_=0@g|@wqrZ8NJSwZ-&Xo3)cYQs z2W9x^JryQjegc^U?IFlBcK zduE^U*~tgleQ;3T_*_#j!FTZZ!L!hX@VM~hVfeBcS~+5|wOV+84EhmR-MR4Bovqe1 zBWA28S1VBZtdBi8%X&Y$^FjEi48GdR?^!p_+c_VZRDThEH9T1*>;uZ4#cE*Y0S7Iw zd$KlACNlmwYep^`EmphxSr>H2*w}*lB=mz*v$w)O#kax74`GX(f{yS-bC+9`PxN7Z zv@<(hz9XI4BnI)_C%XsV%Pk(?3Hm*SP11Ja@k1hu-@Jc#XTtNIoWywM9qq}rM0#>v zebPow%SanJ{Dy>)^XRh$dU0ci9s};}=Gqfmo9J65R3e8j!@RTP9dn=M$6zjSCFjG; z_YnA!`{5QC=Mh6#08M^|T?@?~6ngytx8&2QID_nV{7{mITbg>lM_v!G4vUW{G1DJxAS=p z{C=7@x~d*sI~%-;jy#176rTqDXPms~Ut0?9ukN?AKsm6j4%+g<^{77yU8u5aR(KvO zg$}S24n6?9N`RHf<*1&>Z(#8tuxJG?Q?PO7260((|Bz03KRGeFYH+xkzQLt(qwN7Z zw;q{h+AXY8zPszqLyWNixR;{8hQLcA<4cj3S^UOl9bF1f4&e75!=cU`K0;ng_?pVPnOMZwSF-xzQ7jkrY5Z!FVvXQFCf3B0`ddAavP&*aWJWIt>s zWlB}_h~@bhG%hkA;Hx{`M!uGtj!zwUCdLko|9-tZJKZ~niGIH_|DgMN#mAoHiqI!6 z)#_~6TG(4Xgtv%exn(ZLp^G8+c)CU|)$|S6QZ3+4;uIp^#^ck=JeDwiz+ZK`JK<@O zO-syi^St%4)?lpgTzp37)$&JVisXXG9#Jymr!f9GU?O|$Zy;YJ7Pq^HYL8(asTG<& z!|&fEG&G8_p^2_N=yn;eI~~cG=OSXSCyCF7ZN z#aP|HyXU?jKHBat{-Dft751DDU=OBptZuixXg8PnLWnwNpRic`LK zD0`RBfag5Efylh)AJ3R^A9*lCkt=l*;%AIYSLJO3^>lx4RbF$W>alHZ!ib*riXO5SkvHAfXq%W>C3CXRBu>lmDS0;&+cmTX`}BaWBA!re zABx}o)6!b0KPXr?)L*FoO!8*c9=B};axO!1 z#a|FscVUspxdifA+q_L$9kID>uUva$mQAzh zTgh$B+Nku+m1&&@cFJbr+%G$?^Zqe4*X!MUBcJQNhP7Ac)~z>q@hOP|P4iw@M69nM z%$##0bHk3T0~V8p**$Bv^NgN0hC<8oJ)Cc7-4Gotv=1%UmBBA=6ITMD&G^a zUF>rP=h%_=!ehj)c1@w^;o#^Ia=(m;dA-=B>>r(Ce zz}s#2&+YtFi>_+ZhCQ3`wzj4X*_frpRORszTS)Yc^oMLWqz~kLohuC8#+;Tj54ZB< zy0M)mF%N8x-0nCTsi_0VRil=iNYQb~-l`D%;mtP$&q5FRz=Jr4F8$i+ZxA17YLwX6 zH{0^gOJ0Y>=rT21q0~2Hs_-Ila$~M$IWT3E(oga|HAm^~R?C5#Z%}%hwXact@9+(_ zs>t(J<{@@+7BCWcioSY}aaZy!Ft*Qe=X}C%WK*5Q3r3(vp5%Q3-?L48MOFQh^$ra8 ztoin${|)gOY$~d%P(>Yxplm=S`@Tz6ds9zUoDhyL6^DF}!^VmdInQ?lv3lMi7mWep zGmclUwST|p^=Fpq>)KRo)j({agp-f2i3nG@VJe|&IP$lW{>x%jU8G&*J{+U;1mG)c z=&!|9Me-@jQ+2Pc^kjX4{2VZAbeCB=X@z=wa>Fb_S)~Z)&7op;--lcvLbw+5BRbhO-1@=R(%gg#`ap}(E_)*u6 z@npTqZ)|Ps{XI9vcC&V$H&QV#ct$h>zo{ZPRc(!FL z)9s=s>H^Tx_0XIquwm$g@lUc1dwv1a(P=hj&*VO8iJ{vhVXrWpCwWSt&c1xjJbZIQ*sS>7@G-RBfxPDrw#{Rr|};sd`cb*o1 zpdVvLSS(dD8S4P^%>vdUlLp%}$D9P#ZhV8G@IyN?(8Zkl!n5zq`xP3Dn88fw3$ZT0_xpDKQ4(y0BUHF23{7$BU;O+Iz9|(6HxJ&c2It4!Pr0?t6a$UEnoUmkR z|LCD_FU&h+iB-Ab@b-rnA3YQU4nDa!?~rx0%8lp`pHHDK?}hi9v6-ZwVf0aDNgFd1 zcvzs}5x}M&^M(d;`zLyG2LhkrJy}O@*2nu;=9);qR{D^>xQjVAlJOIIGDdId*J4y@ z31gt+Tx%lyN`L62To?Ui@hr3~^NORrM*C*`&uI8W@DT=$xT&ATw}pC9)N8he8D+%! zM8=}eb3-w43wvtO&}T`EYM3I}1I9^0p~pF`G8QE>;N$t||4xGJOLi8X_?sH&3ws(mo~4bgj@wUzk9 zgSV-yl3%Fy=xsM;S$Qsv4ZE#A{tq{_5uZK<{j^%6-EAMM+IHeA8uDkj_QV=jqVkm? zqx$mPZr8FBBNo3da%u>vuuaIPDO%zI>y$pVN0D2<1mDPN-&1^tC2LudmmvDFYN+y7 z4b{9Wmm)vV2g|T&MQ8a7!s{+nNsP1y@uwtWqz>$kaQ!TLX(?w&B&H(q6j#j+x}`UM z+GaTmV>QO(H|~#6buEijw!|&0*h%QK>=bM$Vgftn*opgKa}B!R>g&b$&BT?&9(aS? zIN`aD!K!PnmVBV2Ky^8_nAR7O`P(fiRnO<=c_r3-av*z>*hnWwD#<_gp1oCdo!X~) z+bfk<=8%c)^d@?*Y3t4263yEBb<&1^mfYVz=i;Jb)-i+FP?7gSmDo4orhRj@?<#x5 zvbN=xd@nR{V4RlJ`Uo;w_G02#Ta_9ANkWe&SFKF>cfZqL5K(twtH3RV@lt_X8gPry z2a$6qHlM_E`3iOIsN$Fpjy; zYREYw@j?3nZ^1!-zPI$V)ctxG{#c%-$KmHnyE)`@OWXVVTD;PJ&VPpE;|BV;CfLUq z?6-#pNGwdso%rKUqh9t$kE(|s07k$5A>6x!eu!rP;K2e|u*_rg}eU4)6d zlrH~T(=L8E+I#-K81kuOsS`(C@|}ZrGQRKXqy5-(BX-(^Y<$V@Z)+s?WF{kUmmNjvi-CDqHya@6ua1)7F4bB>w$5XsOZK(>%j;)Eem)`Z~|Ihvl=UB(afA?y4D^*iXZTI(F!25&}L9EH0rQDxZZ#l&lNl){%17db;rq~-yu=?Cw! zIHEhpdb(^@Pws@#Y7}rXQX&I#<18?e*v0-7Pfjec_}#xz-1Fid)KJ)E@aD_>cw>sHecTi5HTA1YAE8;Ju36`KO#Jx`USd+jP9o6{C-$g1 z*?Zr@vqFzJR};(RcYQzh5{V(2@v29M*2ebtwK`v4k0#+-UGcKv2e zf1b55H}^k=b&hQYw%ohsXkaaQ!`NSfZ;zv=t9n-WwyMrCvs@~%ggvljJvo1wNZgox z6nkH#uV9bSPQQNol{LvXu^+d{gJ#w=+me)>d;5yJ7VLN-J&d_W1H&KC9~)}P9bnFl z*eT;PJUP3!sPc_GxA1)3P*2Wn>;)cSjr%E!K&KvIjk5k0)_5~(yk_CBTD$03bnXe( zXe7p06>2ecPhhXf`lKIOkF2wic@(qO7S{L!>y>!)dDfXeP>ucz>uhD6b6Mvrtn(Sx z>1UnyvCao$RdG4%9K<@och^m*oJ;{dwx#1&t1|#8)kCzdL7;xm zbZ6U&Sk+@(tSWye%JbNBT6k1`eXPDeab@}vOVa%NEbG#(GqveUByIvNS5dzO8?6j` zu5{t-PNkfOn+LN$oY47~XAUzgXHk z!?kh`zyJAzKNWkU>mdH|qr{=Vr7v`Ko68obzm2Q{#_giNI}=`9R}ZfVEKeuAn0}Tu z9WvLHf=+k3Q}*3d^{qAC?WFz(>}|0R*k)5ng@+qs^?zBHr;EJV%~1BZnf5w)K`=>GL((N%>y(F~?=7^5y^SFJ48vZS0M2UO2O} z6c}{Um(+1smG3j^ALF@`{=!-N&34t}sj$aipLDU{P`KZj^Q_Ixn)g< zS!*LQ`iRBS`ZRt2^ZjM%C0g(K?=i2p)zj<#WnGuvp_Zn9i>$kuK0l}a?tIn$t?Etw zlk}63{jbVrcpvR zX{7!->fhBA%idzTVO<}83S>pGI2PRD+6 z2n{?%`#)X6d$^GxaSeD>YiJ#5zdUPMNA1aqIj+_1)uj4%Pytt zgsd-E_9uA!ZpuzlCUrj3)WSP>J{5dEgIzv@XQ8jBgKZ+{=QhgPDSIYZHjuK3($4B| zpDI+oFRbc~v&fqi_K!N@YizIV^M?w&$=Ef5JK0BQ1UKY(R4))+g@3qYfNB?eYUyJO zYKi}kmgmXv=>_CN95QtMq6M{5_ayyaPb^*N(a&#@!4hjd!SDXq8*f$K)%hpvmzPz> zfm<}8yXP#C`0@Yp)tKR^m_%rtM%e zh9alLCYSdTgPI5)qmhvhAO{84YKXm86mXO{&}8&kRZw3}4BGPJ?nK_iv&V4_dql|h z<@^rtT)4hv;oMH8IS)@rtMF|>7Tb}@J|r!_=Qjy}7Ew7Za>MiTVch3#q?^`i0aV8Y6cbc)C_oe;W0k zQyyPju>KV4Z=?Pz)Zak;$<&XHR>ikczlr(<)NA55us7#ZNPW?n4^Y2^`je=Cf_%vF z)On5i)2X+E-|&%He=_w&_pGA+Zt72={>PlbxrI7=sh>x^z5K@aGwa_*{q5BMl=^<^ zPo@4ge8LIT3Bz|qj&y}<6$_yWv;I`-ze@d+)IUP~+o-<^-*6)J`%`~B^#*F5h47C}IaJC}IX`opR3r2aJOPr+|2r2c)> zzm>V;rAc$M>q02pWn9x}$ zI-TDGkn?Zx`(}PG$B!l7C-oM7e?V-6|Dj2p!0#wxEno0^62A-aLF@Vbzxk1a;1m2s zY;TKsFNF9;Z(1B>;tQ=}9fOqY7d<(Dg|bE2$w$}^pF6d%_G9F@x$v#?@eAwwDLt9I z(dFE~5UnK_9xF-9UZRDKC|mk$`UBYGleMr!uO%#TmF6gX|B^5gzwdxw9m z`2HdjBt|T;;zsOS_Pf@2<(rt?IL&459f@6&PcB##WhIo=V{5hUQ?IuW2e&PbUf)6- z-0TN>Y(!2^;!cnPsA%N*uiVn9CT;M!!z_oyodH|EPow z>x6e(fVGS*F>yEXd4sxxpq1swJobMNNS$NM0p6}V#vJUcJe`A~k-1vdvsH|R-LgyM zjvYIgI0~__C?gBoeg*CE0nGM4mJ`rD4`U8_1IGk7P2(S0ve@({#sm^19{+(FjPvFGTg*5asY#uwUxpK7Bh3yVZp0%V_mC@%%6`hbmj>x#f;@9m1*3q<;xjaIhGuE*t+$29FG!Hwu z-VgGA594ju990jQF@b;2k+2QQ&$Y8h@78Q?XuuaW$dc>T(#A?Ip7_l5@f&Vv!9R|A zWxUsJQ{->vbxwi*qBuhx6Q;Ui2U)xVbGOD`8@dQN%wAt0*R=Z{hVYT(N~?Yq^BYXt zOJ&RX>8o?4hc4<`OALYiB+ekCOJtwpuUxp$eIHl)!mc=|?v3M47DZlsl5vLbdtN1X z7`d-5o$?CF&6K|Wc)5Nd<=B|za_(l-BYkGb`tXml zg*Nfa$;Xhrb;qTBOX%|;G| z$S^Z!@@KsyFCba=`Hjcyz=Aa|Wqj9`RK13LC&>xnz89k@PR_Jc^td`_VPZ@D-;G1x z{JkaYqwkL8{m*xHefxLDsF%O1s(G_W_O-l8%fB<)p80O;Fa9up$OY_Q;FL8qYQ6Zg zL%Td{VxLr<5;GHi7ao@TOfEbefvpjV&0)j#uw#Qr-^aA zz}`@OfzqF&OxAKHmHb%FytEF^Bc>MJx>WM(nuKRkjis!!GxFA~#sZJ8>5!DAxnHJC zVuO!FOYX0n1sC5w**HkK>HCr&dG=a~9R4@9~{F@pb=G z;M7m)@6&H7wsIr)Vj2f_oFb(6Vbnn%=~E?*;b~!_AHQV%=TVo(HbO z7j9zCef1+o5nrlclvVm1SvecxzQ9bpy!zG8tnSBf63V-2```lVj_p{KZ+;<@G6xbjm z+}N~hCHG36M}T{YC0)z6kNySb9ej6D?;FwUR!dzMv9ZpQFzD*aGi`EidiTDJ+Ip+f zFTxW-S4q%MK(D44XSgfiTx4EWW0J?W`H-rE4&30@q%}u4G&5W1Nbdh}7zLEeoF2sn z=)jH-l}kL9JG;$yza{tZY%if1iJPTDGb!#p!FRRfi;2x#!TKAlSJIB;5lY{`1$SNe ztu4I&;)$N?{p8@bV1o>{A71w#i&NHL1Kd)9uf#S2wBj(nr2k8BP8)a$&c|Z|aQ5!| zS*=@3bAK2fgfo4I;LP6eT6oWd^B2GeIA!0-`~(hN_*54c-3p)H0$j&Khva=)1Lv7z zna^LC&q8d5&ZxudwlKziQ*W9vSmFbzMjbIx@$m!}B9jG9P0*_oTB$K{B6U-Z|AJ<7 zt!W3EnOCwkxoYf^6xMBP&0-Hz@GJN}#CIpKdq?n1Y^ZzgztH{DLEJ8YhR;U=U+7xe zh1U6J)`|Qu*ZF(uid=V?bb9%oCi*pFx&BIPU1v!YYmR2^F~o0Uy%!6tx((Y)Xc;^i z5;u1}Inb1)Lf2v|`fpV}&Jy~b1Mc-roHGc{i5xeR|6CUaicB&(dJ6u7`Ydyhsk63j z<4zIyK=QEB>CDq%%mS|-&P18~vunsDy#AX0$1#72M`F7>8ceyCX5>N39g!2W8fPH? zl0?=eyMIZU$j#57WwW2s-g@H;rff8d=^y@ZzX?B|8yKS5WN0?k&0Q|$yTjkZ>!LR% zIL*1g$J`q?OP-j+m>FtMeAKKninUY*`o1yLzAO0dqh!5tLEzn(;JdS({?Q#yk8k$? zRo)L8H~YAE5aT$B(bh;@kBnAdeiL4k7ZjtdOZU+GK zc<{6x8~GGCYSZEl%uA4biDYEz6!1A2ycR;slQ<6>kflN=#~H&M{~Z}W%~;7g&F8OJ z6SjlkeA7Ad5V18Hp%bYiFvtw9<;CxSAu=JL3qtfBkg@g9MQOW#^znWkpR_%}+?(Kq zQv8^W*zn2V{_1w*k^z6{fVPX7o7RglXA{e`rf1*8JVdS?v1sLPft$!x-o?{TJ@gL` zcQqDBUYO#3I=L6cVVs2yOk9WTfHPS^I1{tyOg4Gxf%VVHxfi~{Cm2WFX}^_llE2pyU8F}%#@ zLHc{;J2PJ!+@-i@gFDG%ZAEu*p&I_7oRhlpjwaz9u}L0E59p2==niwenL~k}!>~Xn zvaZ|7P2JM&U#%v__!jb8>Ofb9YqHeqlf8oR&31bN?am`OBy)@sunJ+Lg=URgA(jsvzks(9mysMKrrWoUypUlTBA3nky^VNXu!hSbr zMD~*N6QnJHi|gJI(7w|>mUc3}=oM*ezMCAlFKM{>j{CEM^KyAcn*IJR*e||n?grKp z>en@AWRTYTWV>j)6<90*e+@x9WIOEy{|@%x&3WED%IxnD<$@RNNOunSU)k<&tC%?1 z_dWhUd@Os?J6u8fkeFzEK$h%q%^AfSL?=0nWAtIxtG!(IHD#;l%Pa@~n}%{;le$MJ ze=b!1!>!(Xficqbe8qDyL+%VoWvY&^?Y zLAz;(>yKkD$-O_&r`V@k_Wiupt~uN-A^Q}#hIGygz)I#R&nry0INTlBZ6Vl%;3D|` zPGpPKf=%(`_Nm-EDlob|2%{v^k;RO}Tv-T`2wLbcf?-IhWu#IS5DgvV3-QH?k_AySu?L4>$^)2^_~>qOTvf zIR%z-=089Kq4lMjHsy%m8pWOzng5^gv&01@*RUg6=<@Q}SD{Oh>1=qKH2Fe|$=^F% zrtVKRRv|wGzQw@T9BW#xzKJ-utTk^dFlOCm`ID3*o22}D$}0l8XNT*hTr)-?<)bMl zcQa7`mE0h_o$hevEBpPDdl!;7BHzTGx$ymE+WL+;@;_M)i9rNn5h~jpd-ZjCBQztl z?WcY-Fm2IlitOC;C;e4%?mlXKAT6|Zt?yoM_{U}(coH`FtM`8r; z2g~MCb{}PCn=dc7+0FZqUEYDN3&qw#`A{Nf{9nkKs>}B%3a*5QYLFpM262k4+0|ge z$6+iYht?cNY+vCc@FKFOG?FuT(59RPlD%iM&a^&yBeWrPyuisL=lp;t4#Tc3;U60`=rH)-q3QvwQRY811dri21?#A6=9$gCr`5t+=2#h__D*9d<@_ax zLvYo^NAM$O9~Lr)Ow(_aXNU3gWK%91yCYP4A!n56=b)=v<}32hVLVJfoR36K2)>iu zBDSz-KyF=Q=bGyC^(Pwi~s zFMOm$ahzQ>{iK7!W5jl|#ZMAnXbWdj#XpieiFz^CF>E@~2geGOZzr&A*c_l`@_(8C z_^if}0Uu@z&w^h9)8JF);4mUs6Z=o@X8N;*?7go-^Rv0f1#!TC!U>!Yx{579oF*Hi zSaSvP54$hBmAOcq+B~x=zWzW{Zyt12NIq1b>Rko6!>1y)okJA+u++NoE^RFcb$NSmYw&b7Xr8yd;WW5gRDV(AMpWp zpYpH0@bG^U1Jm%^EckC$`nh}umVaMF9lp6~ht|xt)&=hNPVd}ZkW^d2oJ_kTEoj5p zV)RWrt#zW$5J;ESZE1Y6$aPJOiMve&iM79H?E%gb`S7iR>9uEZc5chkXDp0dE^E z-iPy!_@QrO<^5TYEKZy84*4KoGoN_AJI*QJzME__zCP#i<^iaU7VvG-*ON(?e4&5w z{%+#`ZxH|gp7?(U@&8`L|KA|~Urqe~EcE$T;{R_D|KCOYU+j{@k2z=5S4!M6MRG}6 z*#{`T58Rwbc1zr@jq*h^lGlgmdd~NrHR6MJSrgoIEUL>x-MjgOtMmiARch5_h zDsi|qCE97tD3kjn$j{hy9vkO4xr6E0IWq56i_?jxlZYa(Z7ZL${CZXRi^ z`wh>cgB<9o%XYBbm%#mtCZ7@uL$-@f+JekkPMp<*X*Zp;f^h?JafdNi?hy;g?k(g2 z1>@os)Das=;@Z0kX4JlD>FNG8a#`#`fw9;IA=x3acRuk|d~Z{K&q-0$r#hZ{#Zxj^Q z-f8=M9e<8suH#MQlxs_h-g8NEFLSQM8E$8;0UM>K@d)!^&PE6F>lAa8xlUc=oN?Y7 z@AhkHWfRCv=#V%JZ7u-E@2M*^A-X&ezv+c8NjEqHUk!b_ClNdN(u7yWfpJ!70eeem zVUabx%4tn0D}WY+eg(!RZr@1-w^7(Mz1Uk!cMqd&C$?z^^!QV9UhH~N$ zdL>lnZfmdTd#Q5)+RA{g3WD`HyBVOZKc?wlv&YeB|Hryi+I~P=`rF|;lWfXev9l5> zZ~Gow5;*Q=FegPX-boL>!;R^z`__O2;|F)g|*2r?s>8a5b#6!fsRC`>yg?k|-*Ula}B6rtm z{7Lq5gr3>|E#A#pvZdI`LTm93Qj$|g~^GEnx}9MK{e`_szp2J7@^y(R zjXuGcAGoESpSi~w!pF0o!JcIwe3|!~K$HWud*uL&f z$TcUt>|qQk`xEPte$ao0>#g3@lNhqYy$c`Sja;ETJBx4eMbF1ho81SXjj2nQX z#QTtgqr0vbpDoRp!nm2C`IHXSr9biU%<+y6xMYjm18jR!E^&ia`khN0bO`$ovToUX zCSPv{xlQi#eA1c*n)lO?)0F79^ep?3_)q|sDQ?*Vm-YRNaRrXt*#u4{7e~&Dq`C_j z2OH6h>;3bBAGl%{^iz5dqsH z@ilkY@&imWe^DwGEap-USBv}``Hh_1*qs@4iHUYdQ8D8d! z?Q9T-YbSRQ+6lzI$Xk~@WcU6{G$T5|=6;j55(mCI_ep5@(i~sPx?+xA+SHF!`t6e2 z053Pjn|>Dh+ik9)iQLZ`>PR21M+0Sz+*h-nGQsx?tOs5&1n&!$C2;gwIV_ssERb)O zoTv2F)Rnu_nxV@L*KszJ+$XcY`pf-2L!GO0twMKLY+${i-wOjU;lHL#S+LsWNe$x9 z=KeK(DCkXS1DIkr1nxztVc$UZxbQDVZD9XwDL##z^VoyP({na(=NfiUl+Ba-0P$RrbyTt^X9YQalki2|*h7=a+m`(7iSTk^IOjx?IrD^1Hu-I3KN&iBl$2l`5cQe?@L!Ce@{TM!vyc5|o zgt514aa9NQs=8H-zlt?)XZ(-&{m^3D`f0?GWG-*()6RRL59v?VofXVKmfwT9yDS-D>{WlpmD2<=5L2IOCg@jm!3j#;i z?Eai}N*#2M;d(q^mx}&8iY)lrn(A((e$Z}R?K+ws?8oW;igI9Ugktb=S7+#+pR0LK z?i4cTL5yAQZ4}x47V9_p7Z{lDc8Ts5nP+p0J~PXRw~HJf4qlc4L-7a6do*L5AB5U% zkvh`O&Qb1QJ2M|8+2||nkgd}0Z?qHt@qrM}JTA7Xw2N|k#pj0JuEvAV&iAJ6z&=qw ziDO^BgE5p#iLN0nxuVA??r0+~W|ui{#t-bjIE)Rzx0JcceaAu%9q22m!@gvfs}sAd zAYl9ahI$p$BWHF^Gka1}x0yW-soTssP}d-AtObF(9Kfn>UVwei{>?G&ku}G>_Zr

    O0iX$kJZ7TT~+Dz;eb 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¥#>hMouRD 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

      !>SmUBb8oRw23Y&GkLo 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

      rOHuU!b*3kPw z?}OSww8k#l1V6}WT7P%KO@EL3&GqnG4Wd7Y_ZeN}KRgq<1ZJ2=vPs;#*}qQZ^F1lHjvCH>-J{Iv@uA7b$uetMlpZy)yW=|5%dg5)xfg|kQQ_n?o^m_K_#GvKyJ`_ z(0))0FsOf;XK%s2Vk_zmazD@B zu%71mmsv4%pR-{++bxz$#*z`Q`xeB#NnqXZXT_-bzeI6IU(88hYUBX|c2G&oT(JiB z8QvL;C3DOI9hVt7W=0wd^l1xpWDE3g3v_p;1&s!&IhKcT=wfIA<{dT681!M%-n?Ib z1#=y2Ru!ZC**vHz3qXH`y7N^C^Xt&!ZVJO10qcqx$eFQJ4&{Lfg^yv6fnm>MF3&Q; zy^m!icpqb3D3_MvA!P-AX&p}c0<=#-`z9=d8%AxekdieXWqE|+gFmZ6JsGR5g+JCP z$OAnSWt)StJ%aFI8^^HMMS3XXunuQ8!9<&LSVM7Ge{tA95%pBkS0lN8)amT4JTsyX zxPhA-Wn5i2IgAa5b6R&c7YA~K9s<1!Y6l_b)#9EI6V<9;81@?&LmpV`Gwg#f?8`6< z{4DUZz|R6d3;c@VR}8;m_!Yyi7=HQi%ZFb+{PN+K55Ic&)x)nIe)aIH$3B?`%P{oY z_}j!5^8FM>aU75SqJ#!nhIrDcU}&QY!FM5eE(Gs| zh`$hd8BrT>lOs%yFge2H2$NG7nx@5weH0`1FN`;Xu)kwOSuV{GRZ}!gJA*Q9tTf&S z9_`R)jpSrn@YfHIa6!1Ova4KFpVa2#$+R? z0&Th)ln1$kZp}()+!&F+5#fvQ_-r`)9oR0WQ%t8IM7x;rMgIZ(xyaeNuim&vN%R~LRTyz1r;6%!P? z-NUBc!`9uy1^+he__yI?KIgDpw|&^Oeb~Aku9`hw#j|ozwsYHt4{P+;2j{Lf9C&;< zPso&SIdMz2Z8>X~F>)2kyzgrY9vc>vOCwdfM~AsB!>C5prePtP>Y#Szv5;=mQH@^) z6Y~XEGc52E)WN#yVbl6yu9_0Sp2=IQhqq*iRTPto=@8$#cDUf-VeaAKb}h3dZqLtF zTMRv0oXM=?F>Zs5S?*dOTwbbB3JLHDmyaZ6LW1?)VKKv+un}J>g!OKp?_td;ooU&y zF!n$xan>iaTJ-8py_W2YTUBwoCBu9t&$rhex2#pXCl@9c34)<1CqGlLEwJfj`TChF z_6vOQiXCz7OcS(|Pif7s z(jB!;QCT=#HGkM+AKrJ{aKWv^+%3a`e9x`J$8H_YGCA^xb@{{k(zUZPQ^2E4;VfRe zv~3JomA5RY%XSvK>)5LLE@5n@NiZm7?Cy}<0q@;Gt;K6|`@F|z?${A0$ek%Bfki3h zl{1E`emlIoB}pA#s#O$BA3h{!t?fgz_xewDdt%XzqRTphH2ceIpHNo?64(6y=^NGA6L?I6&3QvRRo-?^f~<6lb*}Z zmy@ORIcp-NI$rWlbxL|u%B1R(jfI&3rGpjw;?W7X_+e}OusLwrw42&9H2E27L~WWF zW@%O%n~7c1vaqVrl-{L1=w3yk4}IqX;>{;i=6Al- zî=t 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 apbr9l5a@$I9|Za!&f@0!2bblsf_Ue diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index dd30de0..da6c74e 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -2,6 +2,8 @@ import { CommandHandler, cmd_t, sahara_mode_t, status_t, exec_cmd_t } from "./sa import { concatUint8Array, packGenerator, loadFileFromLocal, readBlobAsBuffer } from "./utils"; import config from "@/config" +let root; + export class Sahara { cdc; ch; // CommandHandler @@ -156,6 +158,7 @@ export class Sahara { async downLoadLoader() { + root = await navigator.storage.getDirectory(); let writable; try { const fileHandle = await root.getFileHandle(this.programmer, { create: true }); @@ -172,7 +175,6 @@ export class Sahara { try { let processed = 0; - //const contentLength = +response.headers.get('Content-Length'); const reader = response.body.getReader(); while (true) { const { done, value } = await reader.read(); @@ -192,6 +194,16 @@ export class Sahara { } } + async getLoader() { + let fileHandle; + try { + fileHandle = await root.getFileHandle(this.programmer, { create: false }) + } catch (e) { + throw `Error getting file handle: ${e}` + } + return await fileHandle.getFile(); + } + async uploadLoader(version){ if (!(await this.enterCommandMode(version))) { @@ -213,9 +225,9 @@ export class Sahara { } console.log("Uploading Programmer..."); - // TODO: change to auto download - //let programmer = new Uint8Array(await readBlobAsBuffer(await downloadLoader())); - let programmer = new Uint8Array(await readBlobAsBuffer(await loadFileFromLocal())); + await this.downLoadLoader(); + let loaderBlob = await this.getLoader(); + let programmer = new Uint8Array(await readBlobAsBuffer(loaderBlob)); if (!(await this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING, version=version))) { return "error"; } diff --git a/src/config.js b/src/config.js index 3f767ee..6e6f661 100644 --- a/src/config.js +++ b/src/config.js @@ -3,8 +3,8 @@ const config = { // release3: 'https://raw.githubusercontent.com/commaai/openpilot/release3/system/hardware/tici/agnos.json', master: 'https://raw.githubusercontent.com/commaai/openpilot/master/system/hardware/tici/agnos.json', }, - edlLoader : { - url: "", + loader: { + url: "https://raw.githubusercontent.com/bkerler/Loaders/main/qualcomm/factory/sdm845_sdm850_sda845/6000000000010000_f8ab20526358c4fa_fhprg.bin", }, } From 3f3689ee6cc6aa0a979460ca3b48b542c8cc1206 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Tue, 19 Mar 2024 23:21:54 -0400 Subject: [PATCH 059/112] throw when disconnect + resetuserdata --- src/QDL/firehose.js | 18 ++++++++++-------- src/QDL/qdl.js | 6 +----- src/QDL/qdlDevice.js | 30 +++--------------------------- src/QDL/usblib.js | 6 ++---- 4 files changed, 16 insertions(+), 44 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 2ba90ca..19c11a6 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -347,17 +347,19 @@ export class Firehose { } - async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}) { + async cmdProgram(physicalPartitionNumber, startSector, blob, onProgress=()=>{}, userdataReset=false) { let total = blob.size; let sparseformat = false; - let sparseHeader = await Sparse.parseFileHeader(blob.slice(0, Sparse.FILE_HEADER_SIZE)); - let sparseImage; - if (sparseHeader !== null) { - sparseImage = new Sparse.QCSparse(blob, sparseHeader) - sparseformat = true; - total = await sparseImage.getSize(); - console.log("size of image:", total); + if (!userdataReset) { + let sparseHeader = await Sparse.parseFileHeader(blob.slice(0, Sparse.FILE_HEADER_SIZE)); + let sparseImage; + if (sparseHeader !== null) { + sparseImage = new Sparse.QCSparse(blob, sparseHeader) + sparseformat = true; + total = await sparseImage.getSize(); + console.log("size of image:", total); + } } let numPartitionSectors = Math.floor(total/this.cfg.SECTOR_SIZE_IN_BYTES); diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 6e0345b..3e73c90 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -290,11 +290,7 @@ export function useQdl() { async function eraseDevice() { setMessage('Erasing userdata') - // TODO: revert for this to work - //const erasePartitions = ["userdata"] - //for await (const [partition, onProgress] of withProgress(erasePartitions, setProgress)) - // await qdl.current.erase(partition, onProgress); - //await qdl.current.resetUserdata() + await qdl.current.resetUserdata() setProgress(0.9) setMessage('Rebooting') diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index a183375..0262110 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -1,32 +1,8 @@ import { usbClass } from "./usblib" import { Sahara } from "./sahara" import { Firehose } from "./firehose" -import { loadFileFromLocal } from "./utils" import { AB_FLAG_OFFSET, AB_PARTITION_ATTR_SLOT_ACTIVE } from "./gpt" -function isRecognizedDevice(slotCount, partitions) { - - if (slotCount !== 2) { - console.error('[QDL] Unrecognised device (kernel, slotCount)') - return false - } - - // check we have the expected partitions to make sure it's a comma three - const expectedPartitions = [ - "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", - "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", - "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", - "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", - "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", - "xbl_config" - ] - if (!partitions.every(partition => expectedPartitions.includes(partition))) { - console.error('[QDL] Unrecognised device (partitions)', partitions) - return false - } - return true -} - export class qdlDevice { cdc; @@ -146,11 +122,11 @@ export class qdlDevice { let dp = await this.firehose?.detectPartition("userdata"); const found = dp[0]; if (found) { - const lun = dp[0], partition = dp[1]; - const wData = new TextEncoder().encode("COMMA_ABL_RESET"); + const lun = dp[1], partition = dp[2]; + const wData = new TextEncoder().encode("COMMA_RESET"); const startSector = partition.sector; console.log("Writing reset flag to partition \"userdata\""); - if (await this.firehose.cmdProgram(lun, startSector, new Blob(wData.buffer))) { + if (await this.firehose.cmdProgram(lun, startSector, new Blob([wData.buffer]), () => {}, true)) { console.log("Successfully writing reset flag to userdata"); } else { console.error("Error writing reset flag to userdata"); diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index c282317..0ca36a6 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -149,8 +149,7 @@ export class usbClass { try { await this.device?.transferOut(this.epOut?.endpointNumber, cmdPacket); } catch(error) { - console.error(error); - return false; + throw new Error("Error while writing:", error); } } return true; @@ -172,8 +171,7 @@ export class usbClass { } catch (error) { retry += 1; if (retry == 3) { - console.error(error); - return false; + throw new Error("Error while writing:", error); } } } From db182cae2fbd45f60ff4e78f1521455da16cd9f2 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 00:00:27 -0400 Subject: [PATCH 060/112] delete fb --- src/utils/blob.js | 27 --- src/utils/fastboot.js | 375 ------------------------------------- src/utils/image.js | 15 -- src/utils/manifest.js | 95 ---------- src/utils/manifest.test.js | 75 -------- src/utils/progress.js | 42 ----- 6 files changed, 629 deletions(-) delete mode 100644 src/utils/blob.js delete mode 100644 src/utils/fastboot.js delete mode 100644 src/utils/image.js delete mode 100644 src/utils/manifest.js delete mode 100644 src/utils/manifest.test.js delete mode 100644 src/utils/progress.js diff --git a/src/utils/blob.js b/src/utils/blob.js deleted file mode 100644 index f36551f..0000000 --- a/src/utils/blob.js +++ /dev/null @@ -1,27 +0,0 @@ -'use client' - -export async function download(url) { - const response = await fetch(url, { mode: 'cors' }) - const reader = response.body.getReader() - const contentLength = +response.headers.get('Content-Length') - console.debug('[blob] Downloading', url, contentLength) - - const chunks = [] - let processed = 0 - while (true) { - const { done, value } = await reader.read() - if (done) break - chunks.push(value) - processed += value.length - } - - const blob = new Blob(chunks) - console.debug('[blob] Downloaded', url, blob.size) - if (blob.size !== contentLength) console.warn('[blob] Download size mismatch', { - url, - expected: contentLength, - actual: blob.size, - }) - - return blob -} diff --git a/src/utils/fastboot.js b/src/utils/fastboot.js deleted file mode 100644 index 39101a1..0000000 --- a/src/utils/fastboot.js +++ /dev/null @@ -1,375 +0,0 @@ -'use client' -import { useEffect, useRef, useState } from 'react' - -import { FastbootDevice, setDebugLevel } from 'android-fastboot' -import * as Comlink from 'comlink' -import { usePlausible } from 'next-plausible' - -import config from '@/config' -import { download } from '@/utils/blob' -import { useImageWorker } from '@/utils/image' -import { createManifest } from '@/utils/manifest' -import { withProgress } from '@/utils/progress' - -/** - * @typedef {import('./manifest.js').Image} Image - */ - -// Verbose logging for fastboot -setDebugLevel(2) - -export const Step = { - INITIALIZING: 0, - READY: 1, - CONNECTING: 2, - DOWNLOADING: 3, - UNPACKING: 4, - FLASHING: 6, - ERASING: 7, - DONE: 8, -} - -export const Error = { - UNKNOWN: -1, - NONE: 0, - UNRECOGNIZED_DEVICE: 1, - LOST_CONNECTION: 2, - DOWNLOAD_FAILED: 3, - UNPACK_FAILED: 4, - CHECKSUM_MISMATCH: 5, - FLASH_FAILED: 6, - ERASE_FAILED: 7, - REQUIREMENTS_NOT_MET: 8, -} - -function isRecognizedDevice(deviceInfo) { - // check some variables are as expected for a comma three - const { - kernel, - "max-download-size": maxDownloadSize, - "slot-count": slotCount, - } = deviceInfo - if (kernel !== "uefi" || maxDownloadSize !== "104857600" || slotCount !== "2") { - console.error('[fastboot] Unrecognised device (kernel, maxDownloadSize or slotCount)', deviceInfo) - return false - } - - const partitions = [] - for (const key of Object.keys(deviceInfo)) { - if (!key.startsWith("partition-type:")) continue - let partition = key.substring("partition-type:".length) - if (partition.endsWith("_a") || partition.endsWith("_b")) { - partition = partition.substring(0, partition.length - 2) - } - if (partitions.includes(partition)) continue - partitions.push(partition) - } - - // check we have the expected partitions to make sure it's a comma three - const expectedPartitions = [ - "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", - "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", - "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", - "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", - "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", - "xbl_config" - ] - if (!partitions.every(partition => expectedPartitions.includes(partition))) { - console.error('[fastboot] Unrecognised device (partitions)', partitions) - return false - } - - // sanity check, also useful for logging - if (!deviceInfo['serialno']) { - console.error('[fastboot] Unrecognised device (missing serialno)', deviceInfo) - return false - } - - return true -} - -export function useFastboot() { - const [step, _setStep] = useState(Step.INITIALIZING) - const [message, _setMessage] = useState('') - const [progress, setProgress] = useState(0) - const [error, _setError] = useState(Error.NONE) - - const [connected, setConnected] = useState(false) - const [serial, setSerial] = useState(null) - - const [onContinue, setOnContinue] = useState(null) - const [onRetry, setOnRetry] = useState(null) - - const imageWorker = useImageWorker() - const fastboot = useRef(new FastbootDevice()) - - /** @type {React.RefObject} */ - const manifest = useRef(null) - - const plausible = usePlausible() - - function setStep(step) { - _setStep(step) - } - - function setMessage(message = '') { - if (message) console.info('[fastboot]', message) - _setMessage(message) - } - - function setError(error) { - _setError(error) - } - - useEffect(() => { - setProgress(-1) - setMessage() - - if (error) return - if (!imageWorker.current) { - console.debug('[fastboot] Waiting for image worker') - return - } - - switch (step) { - case Step.INITIALIZING: { - // Check that the browser supports WebUSB - if (typeof navigator.usb === 'undefined') { - console.error('[fastboot] WebUSB not supported') - setError(Error.REQUIREMENTS_NOT_MET) - break - } - - // Check that the browser supports Web Workers - if (typeof Worker === 'undefined') { - console.error('[fastboot] Web Workers not supported') - setError(Error.REQUIREMENTS_NOT_MET) - break - } - - // Check that the browser supports Storage API - if (typeof Storage === 'undefined') { - console.error('[fastboot] Storage API not supported') - setError(Error.REQUIREMENTS_NOT_MET) - break - } - - // TODO: change manifest once alt image is in release - imageWorker.current?.init() - .then(() => download(config.manifests['master'])) - .then(blob => blob.text()) - .then(text => { - manifest.current = createManifest(text) - - // sanity check - if (manifest.current.length === 0) { - throw 'Manifest is empty' - } - - console.debug('[fastboot] Loaded manifest', manifest.current) - setStep(Step.READY) - }) - .catch((err) => { - console.error('[fastboot] Initialization error', err) - setError(Error.UNKNOWN) - }) - break - } - - case Step.READY: { - // wait for user interaction (we can't use WebUSB without user event) - setOnContinue(() => () => { - setOnContinue(null) - setStep(Step.CONNECTING) - }) - break - } - - case Step.CONNECTING: { - fastboot.current.waitForConnect() - .then(() => { - console.info('[fastboot] Connected', { fastboot: fastboot.current }) - return fastboot.current.getVariable('all') - .then((all) => { - const deviceInfo = all.split('\n').reduce((obj, line) => { - const parts = line.split(':') - const key = parts.slice(0, -1).join(':').trim() - obj[key] = parts.slice(-1)[0].trim() - return obj - }, {}) - - const recognized = isRecognizedDevice(deviceInfo) - console.debug('[fastboot] Device info', { recognized, deviceInfo }) - - if (!recognized) { - setError(Error.UNRECOGNIZED_DEVICE) - return - } - - setSerial(deviceInfo['serialno'] || 'unknown') - setConnected(true) - plausible('device-connected') - setStep(Step.DOWNLOADING) - }) - .catch((err) => { - console.error('[fastboot] Error getting device information', err) - setError(Error.UNKNOWN) - }) - }) - .catch((err) => { - console.error('[fastboot] Connection lost', err) - setError(Error.LOST_CONNECTION) - setConnected(false) - }) - - fastboot.current.connect() - .catch((err) => { - console.error('[fastboot] Connection error', err) - setStep(Step.READY) - }) - break - } - - case Step.DOWNLOADING: { - setProgress(0) - - async function downloadImages() { - for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { - setMessage(`Downloading ${image.name}`) - await imageWorker.current.downloadImage(image, Comlink.proxy(onProgress)) - } - } - - downloadImages() - .then(() => { - console.debug('[fastboot] Downloaded all images') - setStep(Step.UNPACKING) - }) - .catch((err) => { - console.error('[fastboot] Download error', err) - setError(Error.DOWNLOAD_FAILED) - }) - break - } - - case Step.UNPACKING: { - setProgress(0) - - async function unpackImages() { - for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { - setMessage(`Unpacking ${image.name}`) - await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) - } - } - - unpackImages() - .then(() => { - console.debug('[fastboot] Unpacked all images') - setStep(Step.FLASHING) - }) - .catch((err) => { - console.error('[fastboot] Unpack error', err) - if (err.startsWith('Checksum mismatch')) { - setError(Error.CHECKSUM_MISMATCH) - } else { - setError(Error.UNPACK_FAILED) - } - }) - break - } - - case Step.FLASHING: { - setProgress(0) - - async function flashDevice() { - const currentSlot = await fastboot.current.getVariable('current-slot') - if (!['a', 'b'].includes(currentSlot)) { - throw `Unknown current slot ${currentSlot}` - } - - for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { - const fileHandle = await imageWorker.current.getImage(image) - const blob = await fileHandle.getFile() - - if (image.sparse) { - setMessage(`Erasing ${image.name}`) - await fastboot.current.runCommand(`erase:${image.name}`) - } - setMessage(`Flashing ${image.name}`) - await fastboot.current.flashBlob(image.name, blob, onProgress, 'other') - } - console.debug('[fastboot] Flashed all partitions') - - const otherSlot = currentSlot === 'a' ? 'b' : 'a' - setMessage(`Changing slot to ${otherSlot}`) - await fastboot.current.runCommand(`set_active:${otherSlot}`) - } - - flashDevice() - .then(() => { - console.debug('[fastboot] Flash complete') - setStep(Step.ERASING) - }) - .catch((err) => { - console.error('[fastboot] Flashing error', err) - setError(Error.FLASH_FAILED) - }) - break - } - - case Step.ERASING: { - setProgress(0) - - async function eraseDevice() { - setMessage('Erasing userdata') - await fastboot.current.runCommand('erase:userdata') - setProgress(0.9) - - setMessage('Rebooting') - await fastboot.current.runCommand('continue') - setProgress(1) - setConnected(false) - } - - eraseDevice() - .then(() => { - console.debug('[fastboot] Erase complete') - setStep(Step.DONE) - plausible('completed') - }) - .catch((err) => { - console.error('[fastboot] Erase error', err) - setError(Error.ERASE_FAILED) - }) - break - } - } - }, [imageWorker, step]) - - useEffect(() => { - if (error !== Error.NONE) { - console.debug('[fastboot] error', error) - plausible('error', { props: { error }}) - setProgress(-1) - setOnContinue(null) - - setOnRetry(() => () => { - console.debug('[fastboot] on retry') - window.location.reload() - }) - } - }, [error]) - - return { - step, - message, - progress, - error, - - connected, - serial, - - onContinue, - onRetry, - } -} diff --git a/src/utils/image.js b/src/utils/image.js deleted file mode 100644 index 370fc33..0000000 --- a/src/utils/image.js +++ /dev/null @@ -1,15 +0,0 @@ -import { useEffect, useRef } from 'react' - -import * as Comlink from 'comlink' - -export function useImageWorker() { - const apiRef = useRef() - - useEffect(() => { - const worker = new Worker(new URL('../workers/image.worker.js', import.meta.url)) - apiRef.current = Comlink.wrap(worker) - return () => worker.terminate() - }, []) - - return apiRef -} diff --git a/src/utils/manifest.js b/src/utils/manifest.js deleted file mode 100644 index 2f6c3d5..0000000 --- a/src/utils/manifest.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Represents a partition image defined in the AGNOS manifest. - * - * Image archives can be retrieved from {@link archiveUrl}. - */ -export class Image { - /** - * Partition name - * @type {string} - */ - name - - /** - * SHA-256 checksum of the image, encoded as a hex string - * @type {string} - */ - checksum - /** - * Size of the unpacked image in bytes - * @type {number} - */ - size - /** - * Whether the image is sparse - * @type {boolean} - */ - sparse - - /** - * Name of the image file - * @type {string} - */ - fileName - - /** - * Name of the image archive file - * @type {string} - */ - archiveFileName - /** - * URL of the image archive - * @type {string} - */ - archiveUrl - - constructor(json) { - this.name = json.name - this.sparse = json.sparse - - if (this.name === 'system') { - this.checksum = json.alt.hash - this.fileName = `${this.name}-skip-chunks-${json.hash_raw}.img` - this.archiveUrl = json.alt.url - this.size = json.alt.size - } else { - this.checksum = json.hash - this.fileName = `${this.name}-${json.hash_raw}.img` - this.archiveUrl = json.url - this.size = json.size - } - - this.archiveFileName = this.archiveUrl.split('/').pop() - } -} - -/** - * @param {string} text - * @returns {Image[]} - */ -export function createManifest(text) { - const expectedPartitions = ['aop', 'devcfg', 'xbl', 'xbl_config', 'abl', 'boot', 'system'] - const partitions = JSON.parse(text).map((image) => new Image(image)) - - // Sort into consistent order - partitions.sort((a, b) => expectedPartitions.indexOf(a.name) - expectedPartitions.indexOf(b.name)) - - // Check that all partitions are present - // TODO: should we prevent flashing if there are extra partitions? - const missingPartitions = expectedPartitions.filter((name) => !partitions.some((image) => image.name === name)) - if (missingPartitions.length > 0) { - throw new Error(`Manifest is missing partitions: ${missingPartitions.join(', ')}`) - } - - return partitions -} - -/** - * @param {string} url - * @returns {Promise} - */ -export function getManifest(url) { - return fetch(url) - .then((response) => response.text()) - .then(createManifest) -} diff --git a/src/utils/manifest.test.js b/src/utils/manifest.test.js deleted file mode 100644 index b7ec3f8..0000000 --- a/src/utils/manifest.test.js +++ /dev/null @@ -1,75 +0,0 @@ -import { expect, test, vi } from 'vitest' - -import * as Comlink from 'comlink' - -import config from '../config' -import { getManifest } from './manifest' - -async function getImageWorker() { - let imageWorker - - vi.mock('comlink') - vi.mocked(Comlink.expose).mockImplementation(worker => { - imageWorker = worker - imageWorker.init() - }) - - await import('./../workers/image.worker') - - return imageWorker -} - -for (const [branch, manifestUrl] of Object.entries(config.manifests)) { - describe(`${branch} manifest`, async () => { - const imageWorkerFileHandler = { - getFile: vi.fn(), - createWritable: vi.fn().mockImplementation(() => ({ - write: vi.fn(), - close: vi.fn(), - })), - } - - global.navigator = { - storage: { - getDirectory: () => ({ - getFileHandle: () => imageWorkerFileHandler, - }) - } - } - - const imageWorker = await getImageWorker() - - const images = await getManifest(manifestUrl) - - // Check all images are present - expect(images.length).toBe(7) - - for (const image of images) { - describe(`${image.name} image`, async () => { - test('xz archive', () => { - expect(image.archiveFileName, 'archive to be in xz format').toContain('.xz') - expect(image.archiveUrl, 'archive url to be in xz format').toContain('.xz') - }) - - if (image.name === 'system') { - test('alt image', () => { - expect(image.sparse, 'system image to be sparse').toBe(true) - expect(image.fileName, 'system image to be skip chunks').toContain('-skip-chunks-') - expect(image.archiveUrl, 'system image to point to skip chunks').toContain('-skip-chunks-') - }) - } - - test('image and checksum', async () => { - imageWorkerFileHandler.getFile.mockImplementation(async () => { - const response = await fetch(image.archiveUrl) - expect(response.ok, 'to be uploaded').toBe(true) - - return response.blob() - }) - - await imageWorker.unpackImage(image) - }, 8 * 60 * 1000) - }) - } - }) -} diff --git a/src/utils/progress.js b/src/utils/progress.js deleted file mode 100644 index ef209ee..0000000 --- a/src/utils/progress.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Create a set of callbacks that can be used to track progress of a multistep process. - * - * @param {(number[]|number)} steps - * @param {progressCallback} onProgress - * @returns {(progressCallback)[]} - */ -export function createSteps(steps, onProgress) { - const stepWeights = typeof steps === 'number' ? Array(steps).fill(1) : steps - - const progressParts = Array(stepWeights.length).fill(0) - const totalSize = stepWeights.reduce((total, weight) => total + weight, 0) - - function updateProgress() { - const weightedAverage = stepWeights.reduce((acc, weight, idx) => { - return acc + progressParts[idx] * weight - }, 0) - onProgress(weightedAverage / totalSize) - } - - return stepWeights.map((weight, idx) => (progress) => { - if (progressParts[idx] !== progress) { - progressParts[idx] = progress - updateProgress() - } - }) -} - -/** - * Iterate over a list of steps while reporting progress. - * @template T - * @param {(number[]|T[])} steps - * @param {progressCallback} onProgress - * @returns {([T, progressCallback])[]} - */ -export function withProgress(steps, onProgress) { - const callbacks = createSteps( - steps.map(step => typeof step === 'number' ? step : step.size || step.length || 1), - onProgress, - ) - return steps.map((step, idx) => [step, callbacks[idx]]) -} From bcd07fb2f6da282920db027b5f3153cc879ceb19 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 01:54:13 -0400 Subject: [PATCH 061/112] cleanup + catch disconnect --- src/QDL/usblib.js | 8 +++++++- src/QDL/utils.js | 6 ------ src/workers/image.worker.js | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/QDL/usblib.js b/src/QDL/usblib.js index 0ca36a6..30af74c 100644 --- a/src/QDL/usblib.js +++ b/src/QDL/usblib.js @@ -103,7 +103,13 @@ export class usbClass { if (!this._registeredUsbListeners){ - console.log("Get in unregistered"); + navigator.usb.addEventListener("disconnect", async (event) => { + if (event.device === this.device) { + console.log("USB device disconnected"); + throw new Error("device was disconnected during flashing process"); + } + }); + navigator.usb.addEventListener("connect", async (event) =>{ console.log("USB device connect:", event.device); this.device = event.device; diff --git a/src/QDL/utils.js b/src/QDL/utils.js index c5e0ef2..4da18cc 100644 --- a/src/QDL/utils.js +++ b/src/QDL/utils.js @@ -59,12 +59,6 @@ export function compareStringToBytes(compareString, array) { return compareString == tArray; } -export async function loadFileFromLocal() { - const [fileHandle] = await window.showOpenFilePicker(); - let blob = await fileHandle.getFile(); - return blob; -} - export function readBlobAsBuffer(blob) { return new Promise((resolve, reject) => { let reader = new FileReader(); diff --git a/src/workers/image.worker.js b/src/workers/image.worker.js index cbbd64a..ce9589e 100644 --- a/src/workers/image.worker.js +++ b/src/workers/image.worker.js @@ -3,7 +3,7 @@ import * as Comlink from 'comlink' import jsSHA from 'jssha' import { XzReadableStream } from 'xz-decompress'; -import { Image } from '@/utils/manifest' +import { Image } from '@/QDL/manifest' /** * Chunk callback From de264abfed3944b2375ded1c28d1d404d5c13745 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 02:11:55 -0400 Subject: [PATCH 062/112] update instruction --- src/app/Flash.jsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx index 4a342f5..36ccfc8 100644 --- a/src/app/Flash.jsx +++ b/src/app/Flash.jsx @@ -60,8 +60,9 @@ const steps = { }, [Step.DONE]: { status: 'Done', - description: 'Your device has been updated successfully. You can now unplug the USB cable from your computer. To ' + - 'complete the system reset, follow the instructions on your device.', + description: 'Your device has been updated successfully. You can now unplug the all cables from your device, ' + +'and wait for the light to stop flashing then plug the power cord in again. ' + +' To complete the system reset, follow the instructions on your device.', bgColor: 'bg-green-500', icon: done, }, From 6acfcb541eadb6a46082ba587bc31a237e738293 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 06:18:35 -0400 Subject: [PATCH 063/112] faster --- src/QDL/firehose.js | 58 +++++--------- src/QDL/qdl.js | 1 + src/QDL/qdlDevice.js | 2 +- src/QDL/sparse.js | 187 +++++++++++++------------------------------ 4 files changed, 76 insertions(+), 172 deletions(-) diff --git a/src/QDL/firehose.js b/src/QDL/firehose.js index 19c11a6..c8d4b00 100644 --- a/src/QDL/firehose.js +++ b/src/QDL/firehose.js @@ -378,48 +378,30 @@ export class Firehose { for await (let split of Sparse.splitBlob(blob)) { let offset = 0; let bytesToWriteSplit = split.size; - let sparseSplit; - if (sparseformat) { - let sparseSplitHeader = await Sparse.parseFileHeader(split.slice(0, Sparse.FILE_HEADER_SIZE)); - sparseSplit = new Sparse.QCSparse(split, sparseSplitHeader); - bytesToWriteSplit = await sparseSplit.getSize(); - } - - while (bytesToWriteSplit > 0) { - let wlen = Math.min(bytesToWriteSplit, this.cfg.MaxPayloadSizeToTargetInBytes); - let wdata; - if (sparseformat) { - wdata = await sparseSplit?.read(wlen); - } else { - wdata = new Uint8Array(await readBlobAsBuffer(split.slice(offset, offset + wlen))); - } - if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ - let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + - this.cfg.SECTOR_SIZE_IN_BYTES; - const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); - wdata = concatUint8Array([wdata, fillArray]); - } - let sts; - sts = await this.cdc.write(wdata); - sts = await this.cdc.write(new Uint8Array(0), null, true, true); - offset += wlen; - bytesToWriteSplit -= wlen; - bytesWritten += wlen; - if (!sts) { - return false; - } - // ??? why do I need this for sparse? maybe because I split and doesn't fill the whole data? - if (sparseformat && bytesWritten < total && wlen < this.cfg.MaxPayloadSizeToTargetInBytes) - await this.cdc.write(new Uint8Array(0), null, true, true); - - if (i % 10 === 0) - onProgress(bytesWritten/total); - i += 1; + while (bytesToWriteSplit > 0) { + const wlen = Math.min(bytesToWriteSplit, this.cfg.MaxPayloadSizeToTargetInBytes); + let wdata = new Uint8Array(await readBlobAsBuffer(split.slice(offset, offset + wlen))); + if (wlen % this.cfg.SECTOR_SIZE_IN_BYTES !== 0){ + let fillLen = (Math.floor(wlen/this.cfg.SECTOR_SIZE_IN_BYTES) * this.cfg.SECTOR_SIZE_IN_BYTES) + + this.cfg.SECTOR_SIZE_IN_BYTES; + const fillArray = new Uint8Array(fillLen-wlen).fill(0x00); + wdata = concatUint8Array([wdata, fillArray]); } + await this.cdc.write(wdata); + await this.cdc.write(new Uint8Array(0), null, true, true); + offset += wlen; + bytesToWriteSplit -= wlen; + bytesWritten += wlen; + // ??? why do I need this for sparse? maybe because I split and doesn't fill the whole data? + if (sparseformat && bytesWritten < total) + await this.cdc.write(new Uint8Array(0), null, true, true); + if (i % 10 === 0) + onProgress(bytesWritten/total); + i += 1; } + } const wd = await this.waitForData(); - const log = this.xml.getLog(wd); const resposne = this.xml.getReponse(wd); if (resposne.hasOwnProperty("value")) { if (resposne["value"] !== "ACK") { diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 3e73c90..1a16c77 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -227,6 +227,7 @@ export function useQdl() { async function unpackImages() { for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { setMessage(`Unpacking ${image.name}`) + if (image.name === "system") continue await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) } } diff --git a/src/QDL/qdlDevice.js b/src/QDL/qdlDevice.js index 0262110..9b1d9aa 100644 --- a/src/QDL/qdlDevice.js +++ b/src/QDL/qdlDevice.js @@ -30,7 +30,7 @@ export class qdlDevice { async connectToSahara() { while (!this.cdc.connected){ await this.cdc?.connect(); - if (this.cdc.connected){ + if (this.cdc.connected) { console.log("Device detected"); try { let resp = await this.sahara?.connect(); diff --git a/src/QDL/sparse.js b/src/QDL/sparse.js index ceaad86..dff2069 100644 --- a/src/QDL/sparse.js +++ b/src/QDL/sparse.js @@ -3,6 +3,7 @@ import { concatUint8Array, readBlobAsBuffer } from "./utils"; const FILE_MAGIC = 0xed26ff3a; export const FILE_HEADER_SIZE = 28; const CHUNK_HEADER_SIZE = 12; +const MAX_DOWNLOAD_SIZE = 1024 * 1024 * 1024; // 1 GiB const ChunkType = { Raw : 0xCAC1, @@ -63,6 +64,7 @@ export async function parseFileHeader(blobHeader) { } } + export class QCSparse { constructor(blob, header) { this.blob = blob; @@ -134,156 +136,62 @@ export class QCSparse { this.blobOffset = FILE_HEADER_SIZE; return length; } +} - async unsparse() { - if (this.total_blks < this.offset) { - console.error("Error while unsparsing"); - return -1; - } +async function populate(chunks, blockSize) { + const nBlocks = calcChunksBlocks(chunks); + let ret = new Uint8Array(nBlocks*blockSize); + let offset = 0; - - let chunkHeader = await parseChunkHeader(this.blob.slice(this.blobOffset, this.blobOffset += CHUNK_HEADER_SIZE)) - const chunk_type = chunkHeader.type; - const blocks = chunkHeader.blocks; - const data_sz = chunkHeader.dataBytes; + for (const chunk of chunks) { + const chunk_type = chunk.type; + const blocks = chunk.blocks; + const data_sz = chunk.dataBytes; + const data = chunk.data; if (chunk_type == ChunkType.Raw) { - if (data_sz != (blocks*this.blk_sz)) { + if (data_sz != (blocks*blockSize)) { console.error("Rase chunk input size does not match output size"); return -1; } else { - const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += data_sz)); - const data = new Uint8Array(buffer); - this.offset += blocks; - return data; + let rawData = new Uint8Array(await readBlobAsBuffer(data)); + ret.set(rawData, offset); + offset += blocks*blockSize; } } else if (chunk_type == ChunkType.Fill) { if (data_sz != 4) { console.error("Fill chunk should have 4 bytes of fill"); return -1; } else { - const buffer = await readBlobAsBuffer(this.blob.slice(this.blobOffset, this.blobOffset += data_sz)); - let fill_bin = new Uint8Array(buffer); - const bufferSize = blocks*this.blk_sz; - let data = new Uint8Array(bufferSize); - for (let i = 0; i < bufferSize; i+=4) - data.set(fill_bin, i); - this.offset += blocks; - return data; + const fill_bin = new Uint8Array(await readBlobAsBuffer(data)); + const bufferSize = blocks*blockSize; + for (let i = 0; i < bufferSize; i+=data_sz) { + ret.set(fill_bin, offset); + offset += data_sz; + } } } else if (chunk_type == ChunkType.Skip) { - let byteToSend = blocks*this.blk_sz; - this.offset += blocks; - return new Uint8Array(byteToSend).fill(0); + let byteToSend = blocks*blockSize; + let skipData = new Uint8Array(byteToSend).fill(0); + ret.set(skipData, offset); + offset += byteToSend; } else if (chunk_type == ChunkType.Crc32) { if (data_sz != 4) { console.error("CRC32 chunk should have 4 bytes of CRC"); return -1; } else { - this.blobOffset += 4; - return new Uint8Array(0); + continue; } } else { console.error("Unknown chunk type"); return -1; } } - - - async read(length=null) { - let tdata; - this.blobOffset = FILE_HEADER_SIZE; - if (length === null) - return await this.unsparse(); - if (length <= this.tmpdata.length) { - tdata = this.tmpdata.slice(0, length); - this.tmpdata = this.tmpdata.slice(length); - return tdata; - } - while (this.tmpdata.length < length) { - let addedData = await this.unsparse(); - this.tmpdata = concatUint8Array([this.tmpdata, addedData]); - if (length <= this.tmpdata.length) { - tdata = this.tmpdata.slice(0, length); - this.tmpdata = this.tmpdata.slice(length); - return tdata; - } - } - } -} - - -class BlobBuilder { - constructor(type) { - this.type = type; - this.blob = new Blob([], { type: this.type }); - } - - append(blob) { - this.blob = new Blob([this.blob, blob], { type: this.type }); - } - - getBlob() { - return this.blob; - } -} - - -async function createImage(header, chunks) { - let blobBuilder = new BlobBuilder(); - - let buffer = new ArrayBuffer(FILE_HEADER_SIZE); - let dataView = new DataView(buffer); - let arrayView = new Uint8Array(buffer); - - dataView.setUint32(0, FILE_MAGIC, true); - // v1.0 - dataView.setUint16(4, header.major_version, true); - dataView.setUint16(6, header.minor_version, true); - dataView.setUint16(8, header.file_hdr_sz, true); - dataView.setUint16(10, header.chunk_hdr_sz, true); - - // Match input parameters - //TODO: multiple chunks in a split - dataView.setUint32(12, header.blk_sz, true); - dataView.setUint32(16, chunks[0].blocks, true); - dataView.setUint32(20, chunks.length, true); - - dataView.setUint32(24, 0, true); - - blobBuilder.append(new Blob([buffer])); - for (let chunk of chunks) { - let isChunkTypeSkip = chunk.data == null; - buffer = new ArrayBuffer(CHUNK_HEADER_SIZE + (isChunkTypeSkip ? 0 : chunk.data.size)); - dataView = new DataView(buffer); - arrayView = new Uint8Array(buffer); - - dataView.setUint16(0, chunk.type, true); - dataView.setUint16(2, 0, true); // reserved - dataView.setUint32(4, chunk.blocks, true); - dataView.setUint32( - 8, - CHUNK_HEADER_SIZE + (isChunkTypeSkip ? 0 : chunk.data.size), - true - ); - - let chunkArrayView; - if (!isChunkTypeSkip) { - chunkArrayView = new Uint8Array(await readBlobAsBuffer(chunk.data)); - } else { - chunkArrayView = new Uint8Array(0); - } - arrayView.set(chunkArrayView, CHUNK_HEADER_SIZE); - blobBuilder.append(new Blob([buffer])); - } - - return blobBuilder.getBlob(); + return new Blob([ret.buffer]); } -const MAX_DOWNLOAD_SIZE = 1024 * 1024 * 1024; // 1 GiB - function calcChunksRealDataBytes(chunk, blockSize) { switch (chunk.type) { case ChunkType.Raw: @@ -300,15 +208,23 @@ function calcChunksRealDataBytes(chunk, blockSize) { } +function calcChunksSize(chunks, blockSize) { + return chunks.map((chunk) => calcChunksRealDataBytes(chunk, blockSize)).reduce((total, c) => total + c, 0); +} + +function calcChunksBlocks(chunks) { + return chunks.map((chunk) => chunk.blocks).reduce((total, c) => total + c, 0); +} + + export async function* splitBlob(blob, splitSize = 1048576) { const safeToSend = splitSize; - if (blob.size <= MAX_DOWNLOAD_SIZE) { yield blob; return; } - let header = await parseFileHeader(blob.slice(0, FILE_HEADER_SIZE)); + let header = await parseFileHeader(blob.slice(0, FILE_HEADER_SIZE)); if (header === null) { yield blob; return; @@ -316,9 +232,7 @@ export async function* splitBlob(blob, splitSize = 1048576) { header.crc32 = 0; blob = blob.slice(FILE_HEADER_SIZE); - - - + let splitChunks = []; for (let i = 0; i < header.total_chunks; i++) { let originalChunk = await parseChunkHeader(blob.slice(0, CHUNK_HEADER_SIZE)); originalChunk.data = blob.slice(CHUNK_HEADER_SIZE, CHUNK_HEADER_SIZE + originalChunk.dataBytes); @@ -331,7 +245,6 @@ export async function* splitBlob(blob, splitSize = 1048576) { const isChunkTypeFill = originalChunk.type == ChunkType.Fill; if (realBytesToWrite > safeToSend) { - let bytesToWrite = isChunkTypeSkip ? 1 : originalChunk.dataBytes; let originalChunkData = originalChunk.data; @@ -346,7 +259,7 @@ export async function* splitBlob(blob, splitSize = 1048576) { type : originalChunk.type, blocks : realSend / header.blk_sz, dataBytes : isChunkTypeSkip ? 0 : toSend, - data : isChunkTypeSkip ? null : originalChunkData.slice(0, toSend), + data : isChunkTypeSkip ? new Blob([]) : originalChunkData.slice(0, toSend), } chunksToProcess.push(tmpChunk); realBytesToWrite -= realSend; @@ -355,12 +268,11 @@ export async function* splitBlob(blob, splitSize = 1048576) { tmpChunk = { type : originalChunk.type, blocks : toSend / header.blk_sz, - dataBytes : isChunkTypeSkip ? 0 : toSend, - data : isChunkTypeSkip ? null : originalChunkData.slice(0, toSend), + dataBytes : toSend, + data : originalChunkData.slice(0, toSend), } chunksToProcess.push(tmpChunk); } - bytesToWrite -= toSend; originalChunkData = originalChunkData?.slice(toSend); } @@ -368,8 +280,17 @@ export async function* splitBlob(blob, splitSize = 1048576) { chunksToProcess.push(originalChunk) } for (const chunk of chunksToProcess) { - let splitImage = await createImage(header, [chunk]); - yield splitImage; + const remainingBytes = splitSize - calcChunksSize(splitChunks); + const realChunkBytes = calcChunksRealDataBytes(chunk); + if (remainingBytes >= realChunkBytes) { + splitChunks.push(chunk); + } else { + yield await populate(splitChunks, header.blk_sz); + splitChunks = [chunk]; + } } } -} + if (splitChunks.length > 0 ) { + yield await populate(splitChunks, header.blk_sz); + } +} \ No newline at end of file From d20d6f276c01364f71db7177a0fc93d3028dc52d Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 06:19:52 -0400 Subject: [PATCH 064/112] fix --- src/QDL/qdl.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 1a16c77..3e73c90 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -227,7 +227,6 @@ export function useQdl() { async function unpackImages() { for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { setMessage(`Unpacking ${image.name}`) - if (image.name === "system") continue await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) } } From 2286663021703a43cacf76a04f249be7f5126b9b Mon Sep 17 00:00:00 2001 From: Andrei Radulescu Date: Thu, 21 Mar 2024 00:17:42 +0200 Subject: [PATCH 065/112] zadig_form update --- src/assets/zadig_form.png | Bin 9582 -> 12389 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/assets/zadig_form.png b/src/assets/zadig_form.png index 346bb12ab65e6dcb0408cc3e97a55508395ad14e..2bc01ee67a009ece92628e4be9718d11e67d1f5d 100644 GIT binary patch literal 12389 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 literal 9582 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 Date: Thu, 21 Mar 2024 00:34:38 +0200 Subject: [PATCH 066/112] zadig_create_new_device update to match tint --- src/assets/zadig_create_new_device.png | Bin 11106 -> 13805 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/assets/zadig_create_new_device.png b/src/assets/zadig_create_new_device.png index 4e48555dd66bb3148011ac63d8563da5acfc7678..1b252f6ee38e27aa5786d41bc94f8d1c82e0e655 100644 GIT binary patch literal 13805 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 From a88caf4b25ef414ffbcedb2b1dd0706e8fa5b5a1 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 20 Mar 2024 19:59:27 -0400 Subject: [PATCH 067/112] update instruction --- src/QDL/qdl.js | 3 --- src/app/Flash.jsx | 18 +++++++++++++++--- src/assets/zadig_form.png | Bin 9582 -> 35318 bytes 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/QDL/qdl.js b/src/QDL/qdl.js index 3e73c90..71aed48 100644 --- a/src/QDL/qdl.js +++ b/src/QDL/qdl.js @@ -11,9 +11,6 @@ import { useImageWorker } from '@/QDL/image' import { createManifest } from '@/QDL/manifest' import { withProgress } from '@/QDL/progress' -// TODO: remove after upload to cloud -import { loadFileFromLocal } from '@/QDL/utils.js' - /** * @typedef {import('./manifest.js').Image} Image */ diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx index 36ccfc8..558cf3f 100644 --- a/src/app/Flash.jsx +++ b/src/app/Flash.jsx @@ -61,7 +61,7 @@ const steps = { [Step.DONE]: { status: 'Done', description: 'Your device has been updated successfully. You can now unplug the all cables from your device, ' - +'and wait for the light to stop flashing then plug the power cord in again. ' + +'and wait for the light to stop blinking then plug the power cord in again. ' +' To complete the system reset, follow the instructions on your device.', bgColor: 'bg-green-500', icon: done, @@ -84,8 +84,7 @@ const errors = { [Error.LOST_CONNECTION]: { status: 'Lost connection', description: 'The connection to your device was lost. Check that your cables are connected properly and try again. ' + - 'Unplug your device and wait a few seconds. ' + - 'If you are using Linux, make sure to follow the instructions to run a script before flashing.', + 'Unplug your device and wait for around 20s.', icon: cable, }, [Error.DOWNLOAD_FAILED]: { @@ -246,6 +245,19 @@ export default function Flash() {

    {title} {description} + {title === "Lost connection" && ( + <> + + If you are on Linux, make sure to run the script below in your terminal before connecting + +
    +            
    +              curl -o- https://raw.githubusercontent.com/bongbui321/flash/qdl/scripts/detach.sh | bash
    +            
    +          
    + + ) + } {error && ( + + + + - ) - } + )} {error && (
    - - - +
    +
    +
    +
    +                  {detachScripts.map((line, index) => (
    +                    
    +                      {line}
    +                    
    +                  ))}
    +                
    +
    + + + +
    +
    +
    )} diff --git a/src/app/page.jsx b/src/app/page.jsx index 95eee52..3c63d0a 100644 --- a/src/app/page.jsx +++ b/src/app/page.jsx @@ -7,6 +7,7 @@ import fastbootPorts from '@/assets/fastboot-ports.svg' import zadigCreateNewDevice from '@/assets/zadig_create_new_device.png' import zadigForm from '@/assets/zadig_form.png' + const Flash = dynamic(() => import('./Flash'), { loading: () =>

    Loading...

    , ssr: false, @@ -104,14 +105,6 @@ export default function Home() { After your device is in QDL mode, you can click the button to start flashing. A prompt may appear to select a device; choose the device starts with "QUSB_BULK".

    -

    Connecting for Linux

    - For Linux, run this command in your terminal prior to flashing your device. - This helps the website to be able to connect to your device. -
      -
    • - curl -o- https://bongbui321.github.io/flash/static/detach.sh | bash -
    • -

    The process can take 30+ minutes depending on your internet connection and system performance. Do not unplug the device until all steps are complete. @@ -133,7 +126,7 @@ export default function Home() {

    My device's screen is blank

    - The device screen will be blank in QDL mode, but you can verify that it is in QDL if the device shows up + The device screen will be blank in QDL mode, but you can verify that it is in QDL if the device shows up when you press the Flash icon.

    After flashing, device says unable to mount data partition

    diff --git a/src/QDL/blob.js b/src/utils/blob.js similarity index 100% rename from src/QDL/blob.js rename to src/utils/blob.js diff --git a/src/utils/flash.js b/src/utils/flash.js new file mode 100644 index 0000000..92b8ed9 --- /dev/null +++ b/src/utils/flash.js @@ -0,0 +1,340 @@ +'use client' +import { useEffect, useRef, useState } from 'react' + +import { qdlDevice } from '@/QDL/qdl' +import * as Comlink from 'comlink' +import { usePlausible } from 'next-plausible' + +import config from '@/config' +import { download } from './blob' +import { useImageWorker } from './image' +import { createManifest } from './manifest' +import { withProgress } from './progress' + +/** + * @typedef {import('../../utils/manifest.js/index.js').Image} Image + */ + +export const Step = { + INITIALIZING: 0, + READY: 1, + CONNECTING: 2, + DOWNLOADING: 3, + UNPACKING: 4, + FLASHING: 6, + ERASING: 7, + DONE: 8, +} + +export const Error = { + UNKNOWN: -1, + NONE: 0, + UNRECOGNIZED_DEVICE: 1, + LOST_CONNECTION: 2, + DOWNLOAD_FAILED: 3, + UNPACK_FAILED: 4, + CHECKSUM_MISMATCH: 5, + FLASH_FAILED: 6, + ERASE_FAILED: 7, + REQUIREMENTS_NOT_MET: 8, +} + +function isRecognizedDevice(slotCount, partitions) { + + if (slotCount !== 2) { + console.error('[QDL] Unrecognised device (slotCount)') + return false + } + + // check we have the expected partitions to make sure it's a comma three + const expectedPartitions = [ + "ALIGN_TO_128K_1", "ALIGN_TO_128K_2", "ImageFv", "abl", "aop", "apdp", "bluetooth", "boot", "cache", + "cdt", "cmnlib", "cmnlib64", "ddr", "devcfg", "devinfo", "dip", "dsp", "fdemeta", "frp", "fsc", "fsg", + "hyp", "keymaster", "keystore", "limits", "logdump", "logfs", "mdtp", "mdtpsecapp", "misc", "modem", + "modemst1", "modemst2", "msadp", "persist", "qupfw", "rawdump", "sec", "splash", "spunvm", "ssd", + "sti", "storsec", "system", "systemrw", "toolsfv", "tz", "userdata", "vm-linux", "vm-system", "xbl", + "xbl_config" + ] + if (!partitions.every(partition => expectedPartitions.includes(partition))) { + console.error('[QDL] Unrecognised device (partitions)', partitions) + return false + } + return true +} + + +export function useQdl() { + const [step, _setStep] = useState(Step.INITIALIZING) + const [message, _setMessage] = useState('') + const [progress, setProgress] = useState(0) + const [error, _setError] = useState(Error.NONE) + + const [connected, setConnected] = useState(false) + const [serial, setSerial] = useState(null) + + const [onContinue, setOnContinue] = useState(null) + const [onRetry, setOnRetry] = useState(null) + + const imageWorker = useImageWorker() + const qdl = useRef(new qdlDevice()) + + /** @type {React.RefObject} */ + const manifest = useRef(null) + + const plausible = usePlausible() + + function setStep(step) { + _setStep(step) + } + + function setMessage(message = '') { + if (message) console.info('[QDL]', message) + _setMessage(message) + } + + function setError(error) { + _setError(error) + } + useEffect(() => { + setProgress(-1) + setMessage() + + if (error) return + if (!imageWorker.current) { + console.debug('[QDL] Waiting for image worker') + return + } + + switch (step) { + case Step.INITIALIZING: { + // Check that the browser supports WebUSB + if (typeof navigator.usb === 'undefined') { + console.error('[QDL] WebUSB not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break + } + + // Check that the browser supports Web Workers + if (typeof Worker === 'undefined') { + console.error('[QDL] Web Workers not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break + } + + // Check that the browser supports Storage API + if (typeof Storage === 'undefined') { + console.error('[QDL] Storage API not supported') + setError(Error.REQUIREMENTS_NOT_MET) + break + } + + // TODO: change manifest once alt image is in release + imageWorker.current?.init() + .then(() => download(config.manifests['master'])) + .then(blob => blob.text()) + .then(text => { + manifest.current = createManifest(text) + + // sanity check + if (manifest.current.length === 0) { + throw 'Manifest is empty' + } + + console.debug('[QDL] Loaded manifest', manifest.current) + setStep(Step.READY) + }) + .catch((err) => { + console.error('[QDL] Initialization error', err) + setError(Error.UNKNOWN) + }) + break + } + + case Step.READY: { + // wait for user interaction (we can't use WebUSB without user event) + setOnContinue(() => () => { + setOnContinue(null) + setStep(Step.CONNECTING) + }) + break + } + + case Step.CONNECTING: { + qdl.current.waitForConnect() + .then(() => { + console.info('[QDL] Connected') + return qdl.current.getDevicePartitions() + .then(([slotCount, partitions]) => { + const recognized = isRecognizedDevice(slotCount, partitions) + console.debug('[QDL] Device info', { recognized, partitions}) + + if (!recognized) { + setError(Error.UNRECOGNIZED_DEVICE) + return + } + + setSerial(qdl.current.sahara.serial || 'unknown') + setConnected(true) + plausible('device-connected') + setStep(Step.DOWNLOADING) + }) + .catch((err) => { + console.error('[QDL] Error getting device information', err) + setError(Error.UNKNOWN) + }) + }) + .catch((err) => { + console.error('[QDL] Connection lost', err) + setError(Error.LOST_CONNECTION) + setConnected(false) + }) + qdl.current.connect() + .catch((err) => { + console.error('[QDL] Connection error', err) + setStep(Step.READY) + }) + break + } + + case Step.DOWNLOADING: { + setProgress(0) + + async function downloadImages() { + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + setMessage(`Downloading ${image.name}`) + await imageWorker.current.downloadImage(image, Comlink.proxy(onProgress)) + } + } + + downloadImages() + .then(() => { + console.debug('[QDL] Downloaded all images') + setStep(Step.UNPACKING) + }) + .catch((err) => { + console.error('[QDL] Download error', err) + setError(Error.DOWNLOAD_FAILED) + }) + break + } + + case Step.UNPACKING: { + setProgress(0) + + async function unpackImages() { + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + setMessage(`Unpacking ${image.name}`) + if (image.name == "system") continue; + await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) + } + } + + unpackImages() + .then(() => { + console.debug('[QDL] Unpacked all images') + setStep(Step.FLASHING) + }) + .catch((err) => { + console.error('[QDL] Unpack error', err) + if (err.startsWith('Checksum mismatch')) { + setError(Error.CHECKSUM_MISMATCH) + } else { + setError(Error.UNPACK_FAILED) + } + }) + break + } + + case Step.FLASHING: { + setProgress(0) + + async function flashDevice() { + const currentSlot = await qdl.current.getActiveSlot(); + if (!['a', 'b'].includes(currentSlot)) { + throw `Unknown current slot ${currentSlot}` + } + const otherSlot = currentSlot === 'a' ? 'b' : 'a' + + for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { + + const fileHandle = await imageWorker.current.getImage(image) + const blob = await fileHandle.getFile() + + setMessage(`Flashing ${image.name}`) + const partitionName = image.name + `_${otherSlot}`; + await qdl.current.flashBlob(partitionName, blob, onProgress) + } + console.debug('[QDL] Flashed all partitions') + + setMessage(`Changing slot to ${otherSlot}`) + await qdl.current.setActvieSlot(otherSlot); + } + + flashDevice() + .then(() => { + console.debug('[QDL] Flash complete') + setStep(Step.ERASING) + }) + .catch((err) => { + console.error('[QDL] Flashing error', err) + setError(Error.FLASH_FAILED) + }) + break + } + + case Step.ERASING: { + setProgress(0) + + async function eraseDevice() { + setMessage('Erasing userdata') + await qdl.current.resetUserdata() + setProgress(0.9) + + setMessage('Rebooting') + await qdl.current.reset(); + setProgress(1) + setConnected(false) + } + + eraseDevice() + .then(() => { + console.debug('[QDL] Erase complete') + setStep(Step.DONE) + plausible('completed') + }) + .catch((err) => { + console.error('[QDL] Erase error', err) + setError(Error.ERASE_FAILED) + }) + break + } + } + }, [imageWorker, step]) + + useEffect(() => { + if (error !== Error.NONE) { + console.debug('[QDL] error', error) + plausible('error', { props: { error }}) + setProgress(-1) + setOnContinue(null) + + setOnRetry(() => () => { + console.debug('[QDL] on retry') + window.location.reload() + }) + } + }, [error]) + + return { + step, + message, + progress, + error, + + connected, + serial, + + onContinue, + onRetry, + } +} \ No newline at end of file diff --git a/src/QDL/image.js b/src/utils/image.js similarity index 100% rename from src/QDL/image.js rename to src/utils/image.js diff --git a/src/QDL/manifest.js b/src/utils/manifest.js similarity index 100% rename from src/QDL/manifest.js rename to src/utils/manifest.js diff --git a/src/QDL/manifest.test.js b/src/utils/manifest.test.js similarity index 97% rename from src/QDL/manifest.test.js rename to src/utils/manifest.test.js index b7ec3f8..f8f14c1 100644 --- a/src/QDL/manifest.test.js +++ b/src/utils/manifest.test.js @@ -14,7 +14,7 @@ async function getImageWorker() { imageWorker.init() }) - await import('./../workers/image.worker') + await import('../workers/image.worker') return imageWorker } @@ -66,7 +66,7 @@ for (const [branch, manifestUrl] of Object.entries(config.manifests)) { return response.blob() }) - + await imageWorker.unpackImage(image) }, 8 * 60 * 1000) }) diff --git a/src/QDL/progress.js b/src/utils/progress.js similarity index 100% rename from src/QDL/progress.js rename to src/utils/progress.js diff --git a/src/workers/image.worker.js b/src/workers/image.worker.js index ce9589e..56d6b23 100644 --- a/src/workers/image.worker.js +++ b/src/workers/image.worker.js @@ -3,7 +3,7 @@ import * as Comlink from 'comlink' import jsSHA from 'jssha' import { XzReadableStream } from 'xz-decompress'; -import { Image } from '@/QDL/manifest' +import { Image } from '@/utils/manifest' /** * Chunk callback @@ -130,7 +130,7 @@ const imageWorker = { let complete try { const reader = (new XzReadableStream(archiveFile.stream())).getReader() - + await readChunks(reader, imageSize, { onChunk: async (chunk) => { await writable.write(chunk) From 7b7b4afaab03953be5841c1332cfc2f55d426815 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 23 Mar 2024 23:19:49 -0400 Subject: [PATCH 083/112] fix --- src/utils/flash.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/flash.js b/src/utils/flash.js index 92b8ed9..79a6503 100644 --- a/src/utils/flash.js +++ b/src/utils/flash.js @@ -224,7 +224,6 @@ export function useQdl() { async function unpackImages() { for await (const [image, onProgress] of withProgress(manifest.current, setProgress)) { setMessage(`Unpacking ${image.name}`) - if (image.name == "system") continue; await imageWorker.current.unpackImage(image, Comlink.proxy(onProgress)) } } From 3cace3a8562f529bf7259181cbf779467255e8e3 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Sat, 23 Mar 2024 23:30:18 -0400 Subject: [PATCH 084/112] fix style --- src/app/Flash.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx index 3289181..402fe99 100644 --- a/src/app/Flash.jsx +++ b/src/app/Flash.jsx @@ -265,13 +265,13 @@ export default function Flash() { {description} {(title === "Lost connection" || title === "Ready") && isLinux && ( <> - + It seems that you're on Linux, make sure to run the script below in your terminal after plugging in your device.
    -
    +                
                       {detachScripts.map((line, index) => (
                         
                           {line}
    
    From f639765653a0ba49f284e0260f9acb09f1a1a21c Mon Sep 17 00:00:00 2001
    From: bongbui321 
    Date: Sat, 23 Mar 2024 23:35:01 -0400
    Subject: [PATCH 085/112] style
    
    ---
     src/app/Flash.jsx | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx
    index 402fe99..c45c12c 100644
    --- a/src/app/Flash.jsx
    +++ b/src/app/Flash.jsx
    @@ -271,7 +271,7 @@ export default function Flash() {
               
    -
    +                
                       {detachScripts.map((line, index) => (
                         
                           {line}
    
    From f68971eb366738f354468ce0b14c3fded604f49f Mon Sep 17 00:00:00 2001
    From: bongbui321 
    Date: Sun, 24 Mar 2024 00:40:12 -0400
    Subject: [PATCH 086/112] fix
    
    ---
     src/app/Flash.jsx | 8 ++++----
     1 file changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/src/app/Flash.jsx b/src/app/Flash.jsx
    index c45c12c..80b95ee 100644
    --- a/src/app/Flash.jsx
    +++ b/src/app/Flash.jsx
    @@ -118,7 +118,7 @@ const errors = {
       },
     }
     
    -const detachScripts = [
    +const detachScript = [
       "bus=$(lsusb | grep 05c6:9008 | awk '{print $2}' | sed 's/Bus //;s/^0*//')",
       "port=$(lsusb -t | grep Driver=qcserial | awk -F'Port ' '{print $2}' | cut -d ':' -f 1)",
       "echo -n \"$bus-$port:1.0\" | sudo tee /sys/bus/usb/drivers/qcserial/unbind > /dev/null"
    @@ -266,20 +266,20 @@ export default function Flash() {
           {(title === "Lost connection" || title === "Ready") && isLinux && (
             <>
               
    -            It seems that you're on Linux, make sure to run the script below in your terminal after plugging in your device.
    +            It seems that you`'`re on Linux, make sure to run the script below in your terminal after plugging in your device.
               
               
    -                  {detachScripts.map((line, index) => (
    +                  {detachScript.map((line, index) => (
                         
                           {line}
                         
                       ))}
                     
    - +
    - - - +
    diff --git a/src/config.js b/src/config.js index 5ce55c5..a94b0a2 100644 --- a/src/config.js +++ b/src/config.js @@ -4,8 +4,7 @@ const config = { master: 'https://raw.githubusercontent.com/commaai/openpilot/master/system/hardware/tici/agnos.json', }, loader: { - url: 'https://raw.githubusercontent.com/bkerler/Loaders/main/qualcomm/factory/sdm845_sdm850_sda845/6000000000010000_f8ab20526358c4fa_fhprg.bin', - //url: 'https://raw.githubusercontent.com/commaai/flash/master/Loaders/6000000000010000_f8ab20526358c4fa_fhprg.bin', + url: 'https://raw.githubusercontent.com/commaai/flash/master/src/QDL/programmer.bin', }, } From e5286cecd9aecd0dbec54a501ea13b67ceb6ecd7 Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 17 Apr 2024 16:04:02 -0400 Subject: [PATCH 110/112] remove web fastboot --- package.json | 1 - pnpm-lock.yaml | 21 --------------------- 2 files changed, 22 deletions(-) diff --git a/package.json b/package.json index 076637d..dc79b6d 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,6 @@ "node": ">=18.0.0" }, "dependencies": { - "android-fastboot": "github:commaai/fastboot.js#c3ec6fe3c96a48dab46e23d0c8c861af15b2144a", "autoprefixer": "10.4.14", "comlink": "^4.4.1", "crc-32": "^1.2.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eaa6712..6ee5b89 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,6 @@ settings: excludeLinksFromLockfile: false dependencies: - android-fastboot: - specifier: github:commaai/fastboot.js#c3ec6fe3c96a48dab46e23d0c8c861af15b2144a - version: github.com/commaai/fastboot.js/c3ec6fe3c96a48dab46e23d0c8c861af15b2144a autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.24) @@ -1079,11 +1076,6 @@ packages: pretty-format: 29.6.2 dev: true - /@zip.js/zip.js@2.7.24: - resolution: {integrity: sha512-RKXojDXeJcqOLLDFYrPYD0z3YFRaLjuOIAka789VVPGcMeCDEQv08ypNThMt+u+R2b9ISyhWiz43UBrgV1ZcbA==} - engines: {bun: '>=0.7.0', deno: '>=1.0.0', node: '>=16.5.0'} - dev: false - /abab@2.0.6: resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==} dev: true @@ -2983,10 +2975,6 @@ packages: p-limit: 3.1.0 dev: false - /pako@2.1.0: - resolution: {integrity: sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==} - dev: false - /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4036,12 +4024,3 @@ packages: /zod@3.21.4: resolution: {integrity: sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==} dev: false - - github.com/commaai/fastboot.js/c3ec6fe3c96a48dab46e23d0c8c861af15b2144a: - resolution: {tarball: https://codeload.github.com/commaai/fastboot.js/tar.gz/c3ec6fe3c96a48dab46e23d0c8c861af15b2144a} - name: android-fastboot - version: 1.1.5-commaai - dependencies: - '@zip.js/zip.js': 2.7.24 - pako: 2.1.0 - dev: false From 07d904a7dbec92fcc61f7b99c1ff3e6252693c0f Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 17 Apr 2024 16:04:19 -0400 Subject: [PATCH 111/112] revert manifest test and image workers --- src/utils/manifest.test.js | 4 ++-- src/workers/image.worker.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/manifest.test.js b/src/utils/manifest.test.js index f8f14c1..b7ec3f8 100644 --- a/src/utils/manifest.test.js +++ b/src/utils/manifest.test.js @@ -14,7 +14,7 @@ async function getImageWorker() { imageWorker.init() }) - await import('../workers/image.worker') + await import('./../workers/image.worker') return imageWorker } @@ -66,7 +66,7 @@ for (const [branch, manifestUrl] of Object.entries(config.manifests)) { return response.blob() }) - + await imageWorker.unpackImage(image) }, 8 * 60 * 1000) }) diff --git a/src/workers/image.worker.js b/src/workers/image.worker.js index 56d6b23..cbbd64a 100644 --- a/src/workers/image.worker.js +++ b/src/workers/image.worker.js @@ -130,7 +130,7 @@ const imageWorker = { let complete try { const reader = (new XzReadableStream(archiveFile.stream())).getReader() - + await readChunks(reader, imageSize, { onChunk: async (chunk) => { await writable.write(chunk) From 334aa10767ae232aa26128358222a4e51987b6cf Mon Sep 17 00:00:00 2001 From: bongbui321 Date: Wed, 17 Apr 2024 16:24:35 -0400 Subject: [PATCH 112/112] fix downloadLoader --- src/QDL/sahara.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/QDL/sahara.js b/src/QDL/sahara.js index 4dcf4fc..5af8eef 100644 --- a/src/QDL/sahara.js +++ b/src/QDL/sahara.js @@ -180,7 +180,7 @@ export class Sahara { await this.connect(); console.log("Uploading Programmer..."); - await this.downLoadLoader(); + await this.downloadLoader(); const loaderBlob = await this.getLoader(); let programmer = new Uint8Array(await readBlobAsBuffer(loaderBlob)); if (!(await this.cmdHello(sahara_mode_t.SAHARA_MODE_IMAGE_TX_PENDING))) {