firmware update

Dan Williams dcbw at redhat.com
Mon Dec 14 09:44:36 PST 2015


On Mon, 2015-12-14 at 14:15 +0100, Bjørn Mork wrote:
> Aleksander Morgado <aleksander at aleksander.es> writes:
> 
> > On Mon, Dec 14, 2015 at 10:12 AM, dailijin <dailijin126 at 126.com>
> > wrote:
> > > Thanks your quick responds,  this is bad news to me.
> > > 
> > > I known the Sierra firmware updater worked with GobiNet and
> > > GobiSerial
> > > driver, but the two driver will conflict with libqmi driver, this
> > > is indeed
> > > not convenience  for my dialing logic. Do you have planed to
> > > support this
> > > feature in libqmi?
> > 
> > Well, it's not much about libqmi itself, but about rewriting an
> > updater program that plays nicely with qmi_wwan and the upstream
> > serial drivers, e.g. using libqmi/qmicli to reboot into QDL
> > download
> > mode and then using an improved "gobi_loader" program to load the
> > new
> > firmware via the exposed TTY.
> 
> It seems simple to implement on paper, but there are a few issues to
> keep in mind:
> 
> - It's very easy to end up with a (soft-)bricked device if anything
>   unexpected happens.  And we don't know what to expect in general...
> - There are no public docs of any of the involved protocols, which
> makes
>   it difficult to recover from a soft brick
> - We don't know how to properly sanity check and verify the images. 
>  We
>   can only upload what we have and hope for the best
> 
> 
> I have never tried this procedure, so be careful and read the above
> once
> or twice before you try it, but the procedure seems to be:
> 

See also gobi-api/GobiAPI_1.0.40/Core/QDLBuffers.[cpp|h], gobi
-api/GobiAPI_1.0.40/Core/QDLEnum.h, and gobi
-api/GobiAPI_1.0.40/Core/QDLProtocolServer.cpp in libqmi repo. 
 Qualcomm released most of this in the GobiAPI drops.  Not sure what
Sierra modified, but it looks mostly the same.

> a) several rounds of model and version checking using
> 
>  DMS "Get Model" (0x0022)
>  DMS "Sierra Wireless Get Model???" (0x5556) [1]
>  DMS "Get Revision" (0x0023)
> 
>   I guess this part can be ignored wrt image writing, but proper
>   download code should verify that the image file matches the modem,
>   both wrt hardware and currently running version.  We don't know if
>   downgrades are supported, so let's assume the are not.
> 
> 
> b) switch to QDL mode using DMS ??? (0x003e).  This is a request with
> no
>    TLVs, and the reply has only TLV 0x02:

That would be eQMI_DMS_SET_FIRMWARE_ID where the only applicable TLV
(0x01) is a 32-bit firmware ID.  Clearly in your trace the device isn't
sending that TLV.

>   < 01 0C 00 00 02 02 00 09 00 3E 00 00 00 
>   > 01 13 00 80 02 02 02 09 00 3E 00 07 00 02 04 00 00 00 00 00

The reply should be a result code consisting of the 16-bit status and a
16-bit code.  Which matches your trace; there is no error.

>   It is followed by an immediate reboot to "QDL mode"

So perhaps SetFirmwareID with no TLV is the "reboot to QDL mode"
trigger.
  
> 
> c) When in QDL mode, I believe you start out in a protocol known as
>    "DLOAD" or "DMSS Download Protocol" [2].  The first thing you do
> there
>    is to switch to another protocl, known as "Streaming DLOAD" or
> "SDP"
>    [3].

Some bits in GobiAPI might be related, but it looks like they take
effect after the initial "Hello" packet:

ePROTOCOL_QDL_RX,       // 09 QDL variant of streaming protocol (incoming)
ePROTOCOL_QDL_TX,       // 10 QDL variant of streaming protocol (outgoing)

There are also the buffer definitions for "unframed" requests, which
makes sense WRT streaming since unframed would mean dropping the HDLC
framing.

>    I have yet to find any docs of this switching request, but
> snooping
>    shows that it is this simple HDLC frame:
> 
>      7e 70 00 00 14 46 7e
>     
>    The "00 00" is a command parameter.  I have no idea of the exact
>    meaning.  I've only observed a 0 so far.

That part is odd, haven't found anything interesting about it.  The
QCDM 0x70 command is DIAG_CMD_RAM_RW (but references calibration RAM)
so that's probably not anything related.

> 
> d) SDP is what the gobi-loader [4] speaks.  It starts with a
>   semi-doumented hello request (0x01) and ack (0x02):
> 
> 0040  7e 01 51 43 4f 4d 20 68 69 67 68 20 73 70 65 65   ~.QCOM high
> spee
> 0050  64 20 70 72 6f 74 6f 63 6f 6c 20 68 73 74 00 00   d protocol
> hst..
> 0060  00 00 06 06 30 00 00 00 de d3 7e                 
>  ....0.....~
> 
> 0040  7e 02 51 43 4f 4d 20 68 69 67 68 20 73 70 65 65   ~.QCOM high
> spee
> 0050  64 20 70 72 6f 74 6f 63 6f 6c 20 74 67 74 30 00   d protocol
> tgt0.
> 0060  00 00 06 06 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0070  00 30 d9 bc 7e                                    .0..~

See sQDLHello::BuildHelloReq():

struct sQDLRawHelloReq {
      BYTE mCommandCode;     (eQDL_CMD_HELLO_REQ = 0x01)
      BYTE mMagicNumber[32]; (QCOM high speed protocol)
      BYTE mMaxVersion;      (QDL_MIN_VERSION = 0x06)
      BYTE mMinVersion;      (QDL_MAX_VERSION = 0x06)
      BYTE mFeatures;        (QDL_FEATURE_GENERIC_UNFRAMED/0x10 | QDL_FEATURE_QDL_UNFRAMED/0x20 = 0x30)
};

struct sQDLRawHelloRsp {
      BYTE mCommandCode;     (eQDL_CMD_HELLO_RSP = 0x02)
      BYTE mMagicNumber[24]; (same magic)
      DWORD mReserved1;      (0x20 0x74 0x67 0x74)
      WORD mBootMajorVersion;(0x30 0x00)
      WORD mBootMinorVersion;
      BYTE mMaxVersion;      (QDL_MIN_VERSION = 0x06)
      BYTE mMinVersion;      (QDL_MIN_VERSION = 0x06)
      DWORD mReserved2;
      DWORD mReserved3;
      BYTE mReserved4;
      WfORD mReserved5;
      WORD mReserved6;
      BYTE mFeatures;        (QDL_FEATURE_GENERIC_UNFRAMED/0x10 | QDL_FEATURE_QDL_UNFRAMED/0x20 = 0x30)
};


> e) Then the Sierra Wireless downloader starts with a part of the
>   protocol I've found no docs for, but is implemented by the
>   gobi-loader.  This is a start download (0x25) + ack (0x26), 
> followed

See gobi-api/GobiAPI-1.0.40/Core/QDLEnum.h and gobi
-api/GobiAPI_1.0.40/Core/QDLBuffers.cpp:

0x25 = eQDL_CMD_OPEN_UNFRAMED_REQ
0x26 = eQDL_CMD_OPEN_UNFRAMED_RSP

>   by data (0x27) and ack (0x28)

0x27 = eQDL_CMD_WRITE_UNFRAMED_REQ
0x28 = eQDL_CMD_WRITE_UNFRAMED_RSP

>   The most difficult part here, is probably getting the 0x25 request
>   right. This will tell the firware what kind of file we are sending,
>   and the size it should expect to receive.  If you look at the
>   gobi-loader, you'll see that it sends several files.

gobi-api/GobiAPI_1.0.40/GobiQDLService/Main.cpp::Run() shows some of
this.

>   The Sierra downloader sends a single complete image, typically
> using a
>   request like this (from an upgrade of an MC7710 to 03.05.24):
> 
> 0040  7e 25 80 1c 38 4f 02 01 8c 36 4f 02 00 00 01 01  
>  ~%..8O...6O.....
> 0050  02 00 00 00 01 90 00 08 cb 4a 46 55 4c 4c 00 00  
>  .........JFULL..
> 0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 01  
>  ................
> 0070  02 00 00 08 cc da 00 08 d1 72 46 55 4c 4c 00 00  
>  .........rFULL..
> 0080  00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 02  
>  ................
> 0090  00 00 00 11 9e 4c 02 3d 99 d0 46 55 4c 4c 00 00  
>  .....L.=..FULL..
> 00a0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 00b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 00c0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 00d0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 00e0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 00f0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0100  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0110  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0120  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0130  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0140  00 00 00 00 00 00 00 00 00 00 00 00 00 00 d8 2f  
>  .............../
> 0150  cf 2b 00 00 00 03 ff ff ff ff 53 50 4b 47 39 32  
>  .+........SPKG92
> 0160  30 30 02 4f 36 8c 6d 11 b8 2a 39 39 39 39 39 39  
>  00.O6.m..*999999
> 0170  39 5f 39 39 39 39 39 39 39 5f 39 32 30 30 5f 30  
>  9_9999999_9200_0
> 0180  33 2e 30 35 2e 32 34 2e 30 30 5f 30 30 5f 67 65  
>  3.05.24.00_00_ge
> 0190  6e 65 72 69 63 5f 30 30 30 2e 30 30 30 5f 30 30  
>  neric_000.000_00
> 01a0  31 5f 53 50 4b 47 5f 4d 43 00 00 00 00 00 00 00  
>  1_SPKG_MC.......
> 01b0  00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 35  
>  ..............05
> 01c0  2f 30 32 2f 31 33 00 00 00 00 00 00 00 00 00 00  
>  /02/13..........
> 01d0  00 00 00 00 00 00 00 00 00 00 00 00 00 01 ae da  
>  ................
> 01e0  7e                                                ~
> 
> 
>   There is lots of interesting info in the above, but this part seems
>   important to understand the reply: 80 1c 38 4f 02 01 8c 36 4f 02

struct sQDLRawOpenUnframedReq {
      BYTE mCommandCode;        (0x25)
      BYTE mImageType;          (0x80)  (used as eQDL_IMAGE_*)
      DWORD mImageLength;       (0x024f381c)
      BYTE mWindowSize;         (0x01, yes really 1)
      DWORD mUnframedChunkSize; (0x024f368c)
      WORD mReserved1;          (0x0000)
};

Oddly GobiAPI sets the chunk size to QDL_MAX_CHUNK_SIZE = 1024 * 1024 *
64, so not sure where this one's coming from.

>   This looks like "byte, le32, byte, le32".  The first "byte" appears
> to
>   tell what type of file this is (see gobi-loader).  The second is
>   always(?) 1. And the two "le32" numbers look like image sizes. This
> is
>   also confirmed by gobi-loader.  Match 0x024f368c (38745740) with
> this:

>    $ ls -l
> /tmp/9999999_9999999_9200_03.05.24.00_00_generic_000.000_001_SPKG_MC.
> cwe 
>    -rw-r--r-- 1 bjorn bjorn 38746140 May 30  2013
> /tmp/9999999_9999999_9200_03.05.24.00_00_generic_000.000_001_SPKG_MC.
> cwe
> 
>   And notice the same sequence in the reply ack, preceded by an
> unknown
>   16bit zero parameter:
> 
> 0040  7e 26 00 00 01 8c 36 4f 02 e7 2f 7e               ~&....6O../~

Your unknown is mStatus.

struct sQDLRawOpenUnframedRsp {
      BYTE mCommandCode;
      WORD mStatus;
      BYTE mWindowSize;
      DWORD mUnframedChunkSize;
};

> 
>   There are two notable differences in the above 0x25 request
> compared
>   to the ones generated by gobi-loader
>     1) the above is much longer
>     2) the above has slightly different "size" numbers
> 
>   The difference is 0x024f381c - 0x024f368c = 0x190 (400d), which is
>   exactly the number of "extra" data bytes in the 0x25 request. 
>  Those
>   400 bytes is the beginning of the firmware image:

Odd; GobiAPI doesn't show any firmware data being attached to the
 eQDL_CMD_OPEN_UNFRAMED_REQ, it sends the REQ, parses the RSP, then
starts sending data with eQDL_CMD_WRITE_UNFRAMED_REQ.  I wonder if this
is Sierra-specific or it it's a Qualcomm enhancement since the GobiAPI
drops stopped in 2013.

> 00000000  01 01 02 00 00 00 01 90  00 08 cb 4a 46 55 4c 4c 
>  |...........JFULL|
> 00000010  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000020  01 01 02 00 00 08 cc da  00 08 d1 72 46 55 4c 4c 
>  |...........rFULL|
> 00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000040  01 02 00 00 00 11 9e 4c  02 3d 99 d0 46 55 4c 4c 
>  |.......L.=..FULL|
> 00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000060  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000070  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000080  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000090  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000a0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000c0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000d0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 000000f0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000100  d8 2f cf 2b 00 00 00 03  ff ff ff ff 53 50 4b 47 
>  |./.+........SPKG|
> 00000110  39 32 30 30 02 4f 36 8c  6d 11 b8 2a 39 39 39 39 
>  |9200.O6.m..*9999|
> 00000120  39 39 39 5f 39 39 39 39  39 39 39 5f 39 32 30 30 
>  |999_9999999_9200|
> 00000130  5f 30 33 2e 30 35 2e 32  34 2e 30 30 5f 30 30 5f 
>  |_03.05.24.00_00_|
> 00000140  67 65 6e 65 72 69 63 5f  30 30 30 2e 30 30 30 5f 
>  |generic_000.000_|
> 00000150  30 30 31 5f 53 50 4b 47  5f 4d 43 00 00 00 00 00 
>  |001_SPKG_MC.....|
> 00000160  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00 
>  |................|
> 00000170  30 35 2f 30 32 2f 31 33  00 00 00 00 00 00 00 00 
>  |05/02/13........|
> 00000180  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 01 
>  |................|
> 
> 
> 
> 
> f) so far we've seen HDLC framing.  The 0x27 data frames following
> the
>   above is sent without framing.  They have a 13-byte header,
> followed
>   by the next x bytes of the image.  In my case, each of these were
>   split in four 0x800 byte URBs and one URB of 1661 bytes (all
> starting
>   at 0040 here due to the URB header, which I have removed):
> 
> 
> 0040  27 00 00 00 00 00 00 70 1e 00 00 73 82 00 00 00  
>  '......p...s....
> 0050  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> 0060  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  
>  ................
> ..
> 0820  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0830  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 
> 0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> ..
> 0820  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0830  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 
> 0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> ..
> 0820  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0830  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 
> 0040  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0050  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 0060  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> ..
> 0690  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 06a0  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 06b0  ff ff ff ff ff ff ff ff ff ff ff ff ff            .............
> 
> 
>   So what we see is a total of 13 header bytes and 3*2048+1648=7792
> data
>   bytes.  The header is a sequence number (le16 or le32?), followed
> by
>   an unknown 16 or 32 bit value (always? 0), the size of the data
> packet
>   (0x00001e70=7792d) and a checksum.  I don't know if the checksum is
>   calculated over all the 7805 bytes, but I assume it is.
> 
> 
>   This is followed by reply starting with the same sequence number:
> 
> 0040  7e 28 00 00 00 00 00 00 00 00 14 39 7e            ~(.........9~
> 
>   Then this is repeated again and again with exactly 0x2000 bytes
>   transfers (notice the sequence number being 0x00000001 here):
> 
> 0040  27 01 00 00 00 00 00 00 20 00 00 a4 62 ff ff ff   '.......
> ...b...
> 0050  ff ff ff ff ff ff ff ff ff ff ff ff ff d1 dc 4b  
>  ...............K
> 0060  84 34 10 d7 73 5a 43 0b 7d ff ff ff ff ff ff ff  
>  .4..sZC.}.......
> 0070  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  
>  ................
> 
> 
>   Until the last transfer which also is slightly shorter to match the
>   total:
> 
> 0040  27 79 12 00 00 00 00 1c 18 00 00 86 54 78 a8 00  
>  'y..........Tx..
> 
> 0040  7e 28 79 12 00 00 00 00 00 00 1c 9f 7e            ~(y.........~
> 
> 
>    So in total, we transferred
> 
>    400 bytes in the 0x25 request
>    + 0x1e70 bytes in the first 0x27 request
>    + 0x1278 times 0x2000 bytes full sized 0x27 requests
>    + 0x181c bytes in the last 0x27 request
>    = 38746140 bytes
> 
>    Matching the image file size.  Good.  What we don't know is why
> the
>    first transfer is slightly shorter, or why we have the first 400
>    bytes transferred as part of the 0x25 request.
>    
> 
> g) The procedure is terminated with a 0x29 request and 0x2a ack:
> 
> 0040  7e 29 bb 4c 7e                                    ~).L~
> 0040  7e 2a 00 00 00 00 4e e3 7e                        ~*....N.~

eQDL_CMD_SESSION_DONE_REQ and eQDL_CMD_SESSION_DONE_RSP

> 
> h) Then we send a 0x2d request, which is not part of the
>   gobi-loader. This request causes an immediate reboot into
> application
>   mode:
> 
> 0040  7e 2d 9f 0a 7e                                    ~-..~

eQDL_CMD_SESSION_CLOSE_REQ

Dan

>   The first reboot will take some time, and I believe it also could
> be
>   followed by more reboots before the process is complete.  Then, if
> you
>   are lucky, the modem will boot a new firmware version in QMI mode.
> 
>   If not, then you are most likely screwed and your modem is now an
>   expensive dummy slot filler.
>   
> 
> 
> Bjørn
> 
> 
> 
> 
> [1] assumed vendor specific version info request. typical result:
> 
> QMI frame #0
> > > > > > > QMUX:
> > > > > > >   length  = 103
> > > > > > >   flags   = 0x80
> > > > > > >   service = "dms"
> > > > > > >   client  = 2
> > > > > > > QMI:
> > > > > > >   flags       = "response"
> > > > > > >   transaction = 5
> > > > > > >   tlv_length  = 91
> > > > > > >   message     = (0x5556)
> > > > > > > TLV:
> > > > > > >   type   = 0x02
> > > > > > >   length = 4
> > > > > > >   value  = 00:00:00:00
> > > > > > > TLV:
> > > > > > >   type   = 0x16
> > > > > > >   length = 7
> > > > > > >   value  = 30:30:30:2E:30:30:35
> > > > > > > TLV:
> > > > > > >   type   = 0x15
> > > > > > >   length = 2
> > > > > > >   value  = 31:00
> > > > > > > TLV:
> > > > > > >   type   = 0x13
> > > > > > >   length = 8
> > > > > > >   value  = 31:31:30:32:34:37:36:00
> > > > > > > TLV:
> > > > > > >   type   = 0x12
> > > > > > >   length = 21
> > > > > > >   value  =
> > > > > > > 53:57:49:39:58:33:30:43:5F:30:31:2E:30:38:2E:30:37:2E:30:
> > > > > > > 30:00
> > > > > > > TLV:
> > > > > > >   type   = 0x11
> > > > > > >   length = 21
> > > > > > >   value  =
> > > > > > > 53:57:49:39:58:33:30:43:5F:30:31:2E:30:38:2E:30:37:2E:30:
> > > > > > > 30:00
> > > > > > > TLV:
> > > > > > >   type   = 0x10
> > > > > > >   length = 7
> > > > > > >   value  = 4D:43:37:34:35:35:00
> 
> (note that all these except 0x16 are 0x00 terminated)
> 
> 0x10 => MC7455
> 0x11 => SWI9X30C_01.08.07.00
> 0x12 => SWI9X30C_01.08.07.00
> 0x13 => 1102476
> 0x15 => 1
> 0x16 => 000.005
> 
> [2] https://github.com/ghassani/openpst/blob/master/src/qc/dload.h
> 
> [3] https://github.com/ghassani/openpst/blob/master/src/qc/streaming_
> dload.h
> 
> [4] http://www.codon.org.uk/~mjg59/gobi_loader/
> _______________________________________________
> libqmi-devel mailing list
> libqmi-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/libqmi-devel


More information about the libqmi-devel mailing list