Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0+
0002 
0003 .. |u8| replace:: :c:type:`u8 <u8>`
0004 .. |u16| replace:: :c:type:`u16 <u16>`
0005 .. |TYPE| replace:: ``TYPE``
0006 .. |LEN| replace:: ``LEN``
0007 .. |SEQ| replace:: ``SEQ``
0008 .. |SYN| replace:: ``SYN``
0009 .. |NAK| replace:: ``NAK``
0010 .. |ACK| replace:: ``ACK``
0011 .. |DATA| replace:: ``DATA``
0012 .. |DATA_SEQ| replace:: ``DATA_SEQ``
0013 .. |DATA_NSQ| replace:: ``DATA_NSQ``
0014 .. |TC| replace:: ``TC``
0015 .. |TID| replace:: ``TID``
0016 .. |IID| replace:: ``IID``
0017 .. |RQID| replace:: ``RQID``
0018 .. |CID| replace:: ``CID``
0019 
0020 ===========================
0021 Surface Serial Hub Protocol
0022 ===========================
0023 
0024 The Surface Serial Hub (SSH) is the central communication interface for the
0025 embedded Surface Aggregator Module controller (SAM or EC), found on newer
0026 Surface generations. We will refer to this protocol and interface as
0027 SAM-over-SSH, as opposed to SAM-over-HID for the older generations.
0028 
0029 On Surface devices with SAM-over-SSH, SAM is connected to the host via UART
0030 and defined in ACPI as device with ID ``MSHW0084``. On these devices,
0031 significant functionality is provided via SAM, including access to battery
0032 and power information and events, thermal read-outs and events, and many
0033 more. For Surface Laptops, keyboard input is handled via HID directed
0034 through SAM, on the Surface Laptop 3 and Surface Book 3 this also includes
0035 touchpad input.
0036 
0037 Note that the standard disclaimer for this subsystem also applies to this
0038 document: All of this has been reverse-engineered and may thus be erroneous
0039 and/or incomplete.
0040 
0041 All CRCs used in the following are two-byte ``crc_ccitt_false(0xffff, ...)``.
0042 All multi-byte values are little-endian, there is no implicit padding between
0043 values.
0044 
0045 
0046 SSH Packet Protocol: Definitions
0047 ================================
0048 
0049 The fundamental communication unit of the SSH protocol is a frame
0050 (:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following
0051 fields, packed together and in order:
0052 
0053 .. flat-table:: SSH Frame
0054    :widths: 1 1 4
0055    :header-rows: 1
0056 
0057    * - Field
0058      - Type
0059      - Description
0060 
0061    * - |TYPE|
0062      - |u8|
0063      - Type identifier of the frame.
0064 
0065    * - |LEN|
0066      - |u16|
0067      - Length of the payload associated with the frame.
0068 
0069    * - |SEQ|
0070      - |u8|
0071      - Sequence ID (see explanation below).
0072 
0073 Each frame structure is followed by a CRC over this structure. The CRC over
0074 the frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly
0075 after the frame structure and before the payload. The payload is followed by
0076 its own CRC (over all payload bytes). If the payload is not present (i.e.
0077 the frame has ``LEN=0``), the CRC of the payload is still present and will
0078 evaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it
0079 equals the number of bytes inbetween the CRC of the frame and the CRC of the
0080 payload.
0081 
0082 Additionally, the following fixed two-byte sequences are used:
0083 
0084 .. flat-table:: SSH Byte Sequences
0085    :widths: 1 1 4
0086    :header-rows: 1
0087 
0088    * - Name
0089      - Value
0090      - Description
0091 
0092    * - |SYN|
0093      - ``[0xAA, 0x55]``
0094      - Synchronization bytes.
0095 
0096 A message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and
0097 CRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes,
0098 followed finally, regardless if the payload is present, the payload CRC. The
0099 messages corresponding to an exchange are, in part, identified by having the
0100 same sequence ID (|SEQ|), stored inside the frame (more on this in the next
0101 section). The sequence ID is a wrapping counter.
0102 
0103 A frame can have the following types
0104 (:c:type:`enum ssh_frame_type <ssh_frame_type>`):
0105 
0106 .. flat-table:: SSH Frame Types
0107    :widths: 1 1 4
0108    :header-rows: 1
0109 
0110    * - Name
0111      - Value
0112      - Short Description
0113 
0114    * - |NAK|
0115      - ``0x04``
0116      - Sent on error in previously received message.
0117 
0118    * - |ACK|
0119      - ``0x40``
0120      - Sent to acknowledge receival of |DATA| frame.
0121 
0122    * - |DATA_SEQ|
0123      - ``0x80``
0124      - Sent to transfer data. Sequenced.
0125 
0126    * - |DATA_NSQ|
0127      - ``0x00``
0128      - Same as |DATA_SEQ|, but does not need to be ACKed.
0129 
0130 Both |NAK|- and |ACK|-type frames are used to control flow of messages and
0131 thus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the
0132 other hand must carry a payload. The flow sequence and interaction of
0133 different frame types will be described in more depth in the next section.
0134 
0135 
0136 SSH Packet Protocol: Flow Sequence
0137 ==================================
0138 
0139 Each exchange begins with |SYN|, followed by a |DATA_SEQ|- or
0140 |DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In
0141 case of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a
0142 |DATA_SEQ|-type frame, the receiving party has to acknowledge receival of
0143 the frame by responding with a message containing an |ACK|-type frame with
0144 the same sequence ID of the |DATA| frame. In other words, the sequence ID of
0145 the |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an
0146 error, e.g. an invalid CRC, the receiving party responds with a message
0147 containing an |NAK|-type frame. As the sequence ID of the previous data
0148 frame, for which an error is indicated via the |NAK| frame, cannot be relied
0149 upon, the sequence ID of the |NAK| frame should not be used and is set to
0150 zero. After receival of an |NAK| frame, the sending party should re-send all
0151 outstanding (non-ACKed) messages.
0152 
0153 Sequence IDs are not synchronized between the two parties, meaning that they
0154 are managed independently for each party. Identifying the messages
0155 corresponding to a single exchange thus relies on the sequence ID as well as
0156 the type of the message, and the context. Specifically, the sequence ID is
0157 used to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not
0158 ``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames.
0159 
0160 An example exchange might look like this:
0161 
0162 ::
0163 
0164     tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
0165     rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) --
0166 
0167 where both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)``
0168 indicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame,
0169 ``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the
0170 previous payload. In case of an error, the exchange would look like this:
0171 
0172 ::
0173 
0174     tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) -----------------------------
0175     rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) --
0176 
0177 upon which the sender should re-send the message. ``FRAME(N)`` indicates an
0178 |NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed
0179 to zero. For |DATA_NSQ|-type frames, both exchanges are the same:
0180 
0181 ::
0182 
0183     tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ----------------------
0184     rx: -------------------------------------------------------------------
0185 
0186 Here, an error can be detected, but not corrected or indicated to the
0187 sending party. These exchanges are symmetric, i.e. switching ``rx`` and
0188 ``tx`` results again in a valid exchange. Currently, no longer exchanges are
0189 known.
0190 
0191 
0192 Commands: Requests, Responses, and Events
0193 =========================================
0194 
0195 Commands are sent as payload inside a data frame. Currently, this is the
0196 only known payload type of |DATA| frames, with a payload-type value of
0197 ``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`).
0198 
0199 The command-type payload (:c:type:`struct ssh_command <ssh_command>`)
0200 consists of an eight-byte command structure, followed by optional and
0201 variable length command data. The length of this optional data is derived
0202 from the frame payload length given in the corresponding frame, i.e. it is
0203 ``frame.len - sizeof(struct ssh_command)``. The command struct contains the
0204 following fields, packed together and in order:
0205 
0206 .. flat-table:: SSH Command
0207    :widths: 1 1 4
0208    :header-rows: 1
0209 
0210    * - Field
0211      - Type
0212      - Description
0213 
0214    * - |TYPE|
0215      - |u8|
0216      - Type of the payload. For commands always ``0x80``.
0217 
0218    * - |TC|
0219      - |u8|
0220      - Target category.
0221 
0222    * - |TID| (out)
0223      - |u8|
0224      - Target ID for outgoing (host to EC) commands.
0225 
0226    * - |TID| (in)
0227      - |u8|
0228      - Target ID for incoming (EC to host) commands.
0229 
0230    * - |IID|
0231      - |u8|
0232      - Instance ID.
0233 
0234    * - |RQID|
0235      - |u16|
0236      - Request ID.
0237 
0238    * - |CID|
0239      - |u8|
0240      - Command ID.
0241 
0242 The command struct and data, in general, does not contain any failure
0243 detection mechanism (e.g. CRCs), this is solely done on the frame level.
0244 
0245 Command-type payloads are used by the host to send commands and requests to
0246 the EC as well as by the EC to send responses and events back to the host.
0247 We differentiate between requests (sent by the host), responses (sent by the
0248 EC in response to a request), and events (sent by the EC without a preceding
0249 request).
0250 
0251 Commands and events are uniquely identified by their target category
0252 (``TC``) and command ID (``CID``). The target category specifies a general
0253 category for the command (e.g. system in general, vs. battery and AC, vs.
0254 temperature, and so on), while the command ID specifies the command inside
0255 that category. Only the combination of |TC| + |CID| is unique. Additionally,
0256 commands have an instance ID (``IID``), which is used to differentiate
0257 between different sub-devices. For example ``TC=3`` ``CID=1`` is a
0258 request to get the temperature on a thermal sensor, where |IID| specifies
0259 the respective sensor. If the instance ID is not used, it should be set to
0260 zero. If instance IDs are used, they, in general, start with a value of one,
0261 whereas zero may be used for instance independent queries, if applicable. A
0262 response to a request should have the same target category, command ID, and
0263 instance ID as the corresponding request.
0264 
0265 Responses are matched to their corresponding request via the request ID
0266 (``RQID``) field. This is a 16 bit wrapping counter similar to the sequence
0267 ID on the frames. Note that the sequence ID of the frames for a
0268 request-response pair does not match. Only the request ID has to match.
0269 Frame-protocol wise these are two separate exchanges, and may even be
0270 separated, e.g. by an event being sent after the request but before the
0271 response. Not all commands produce a response, and this is not detectable by
0272 |TC| + |CID|. It is the responsibility of the issuing party to wait for a
0273 response (or signal this to the communication framework, as is done in
0274 SAN/ACPI via the ``SNC`` flag).
0275 
0276 Events are identified by unique and reserved request IDs. These IDs should
0277 not be used by the host when sending a new request. They are used on the
0278 host to, first, detect events and, second, match them with a registered
0279 event handler. Request IDs for events are chosen by the host and directed to
0280 the EC when setting up and enabling an event source (via the
0281 enable-event-source request). The EC then uses the specified request ID for
0282 events sent from the respective source. Note that an event should still be
0283 identified by its target category, command ID, and, if applicable, instance
0284 ID, as a single event source can send multiple different event types. In
0285 general, however, a single target category should map to a single reserved
0286 event request ID.
0287 
0288 Furthermore, requests, responses, and events have an associated target ID
0289 (``TID``). This target ID is split into output (host to EC) and input (EC to
0290 host) fields, with the respecting other field (e.g. output field on incoming
0291 messages) set to zero. Two ``TID`` values are known: Primary (``0x01``) and
0292 secondary (``0x02``). In general, the response to a request should have the
0293 same ``TID`` value, however, the field (output vs. input) should be used in
0294 accordance to the direction in which the response is sent (i.e. on the input
0295 field, as responses are generally sent from the EC to the host).
0296 
0297 Note that, even though requests and events should be uniquely identifiable
0298 by target category and command ID alone, the EC may require specific
0299 target ID and instance ID values to accept a command. A command that is
0300 accepted for ``TID=1``, for example, may not be accepted for ``TID=2``
0301 and vice versa.
0302 
0303 
0304 Limitations and Observations
0305 ============================
0306 
0307 The protocol can, in theory, handle up to ``U8_MAX`` frames in parallel,
0308 with up to ``U16_MAX`` pending requests (neglecting request IDs reserved for
0309 events). In practice, however, this is more limited. From our testing
0310 (although via a python and thus a user-space program), it seems that the EC
0311 can handle up to four requests (mostly) reliably in parallel at a certain
0312 time. With five or more requests in parallel, consistent discarding of
0313 commands (ACKed frame but no command response) has been observed. For five
0314 simultaneous commands, this reproducibly resulted in one command being
0315 dropped and four commands being handled.
0316 
0317 However, it has also been noted that, even with three requests in parallel,
0318 occasional frame drops happen. Apart from this, with a limit of three
0319 pending requests, no dropped commands (i.e. command being dropped but frame
0320 carrying command being ACKed) have been observed. In any case, frames (and
0321 possibly also commands) should be re-sent by the host if a certain timeout
0322 is exceeded. This is done by the EC for frames with a timeout of one second,
0323 up to two re-tries (i.e. three transmissions in total). The limit of
0324 re-tries also applies to received NAKs, and, in a worst case scenario, can
0325 lead to entire messages being dropped.
0326 
0327 While this also seems to work fine for pending data frames as long as no
0328 transmission failures occur, implementation and handling of these seems to
0329 depend on the assumption that there is only one non-acknowledged data frame.
0330 In particular, the detection of repeated frames relies on the last sequence
0331 number. This means that, if a frame that has been successfully received by
0332 the EC is sent again, e.g. due to the host not receiving an |ACK|, the EC
0333 will only detect this if it has the sequence ID of the last frame received
0334 by the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1``
0335 followed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0``
0336 frame as such, and thus execute the command in this frame each time it has
0337 been received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and
0338 then repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of
0339 the first one and ignore it, thus executing the contained command only once.
0340 
0341 In conclusion, this suggests a limit of at most one pending un-ACKed frame
0342 (per party, effectively leading to synchronous communication regarding
0343 frames) and at most three pending commands. The limit to synchronous frame
0344 transfers seems to be consistent with behavior observed on Windows.