1.. SPDX-License-Identifier: GPL-2.0+ 2 3.. |u8| replace:: :c:type:`u8 <u8>` 4.. |u16| replace:: :c:type:`u16 <u16>` 5.. |TYPE| replace:: ``TYPE`` 6.. |LEN| replace:: ``LEN`` 7.. |SEQ| replace:: ``SEQ`` 8.. |SYN| replace:: ``SYN`` 9.. |NAK| replace:: ``NAK`` 10.. |ACK| replace:: ``ACK`` 11.. |DATA| replace:: ``DATA`` 12.. |DATA_SEQ| replace:: ``DATA_SEQ`` 13.. |DATA_NSQ| replace:: ``DATA_NSQ`` 14.. |TC| replace:: ``TC`` 15.. |TID| replace:: ``TID`` 16.. |SID| replace:: ``SID`` 17.. |IID| replace:: ``IID`` 18.. |RQID| replace:: ``RQID`` 19.. |CID| replace:: ``CID`` 20 21=========================== 22Surface Serial Hub Protocol 23=========================== 24 25The Surface Serial Hub (SSH) is the central communication interface for the 26embedded Surface Aggregator Module controller (SAM or EC), found on newer 27Surface generations. We will refer to this protocol and interface as 28SAM-over-SSH, as opposed to SAM-over-HID for the older generations. 29 30On Surface devices with SAM-over-SSH, SAM is connected to the host via UART 31and defined in ACPI as device with ID ``MSHW0084``. On these devices, 32significant functionality is provided via SAM, including access to battery 33and power information and events, thermal read-outs and events, and many 34more. For Surface Laptops, keyboard input is handled via HID directed 35through SAM, on the Surface Laptop 3 and Surface Book 3 this also includes 36touchpad input. 37 38Note that the standard disclaimer for this subsystem also applies to this 39document: All of this has been reverse-engineered and may thus be erroneous 40and/or incomplete. 41 42All CRCs used in the following are two-byte ``crc_itu_t(0xffff, ...)``. 43All multi-byte values are little-endian, there is no implicit padding between 44values. 45 46 47SSH Packet Protocol: Definitions 48================================ 49 50The fundamental communication unit of the SSH protocol is a frame 51(:c:type:`struct ssh_frame <ssh_frame>`). A frame consists of the following 52fields, packed together and in order: 53 54.. flat-table:: SSH Frame 55 :widths: 1 1 4 56 :header-rows: 1 57 58 * - Field 59 - Type 60 - Description 61 62 * - |TYPE| 63 - |u8| 64 - Type identifier of the frame. 65 66 * - |LEN| 67 - |u16| 68 - Length of the payload associated with the frame. 69 70 * - |SEQ| 71 - |u8| 72 - Sequence ID (see explanation below). 73 74Each frame structure is followed by a CRC over this structure. The CRC over 75the frame structure (|TYPE|, |LEN|, and |SEQ| fields) is placed directly 76after the frame structure and before the payload. The payload is followed by 77its own CRC (over all payload bytes). If the payload is not present (i.e. 78the frame has ``LEN=0``), the CRC of the payload is still present and will 79evaluate to ``0xffff``. The |LEN| field does not include any of the CRCs, it 80equals the number of bytes between the CRC of the frame and the CRC of the 81payload. 82 83Additionally, the following fixed two-byte sequences are used: 84 85.. flat-table:: SSH Byte Sequences 86 :widths: 1 1 4 87 :header-rows: 1 88 89 * - Name 90 - Value 91 - Description 92 93 * - |SYN| 94 - ``[0xAA, 0x55]`` 95 - Synchronization bytes. 96 97A message consists of |SYN|, followed by the frame (|TYPE|, |LEN|, |SEQ| and 98CRC) and, if specified in the frame (i.e. ``LEN > 0``), payload bytes, 99followed finally, regardless if the payload is present, the payload CRC. The 100messages corresponding to an exchange are, in part, identified by having the 101same sequence ID (|SEQ|), stored inside the frame (more on this in the next 102section). The sequence ID is a wrapping counter. 103 104A frame can have the following types 105(:c:type:`enum ssh_frame_type <ssh_frame_type>`): 106 107.. flat-table:: SSH Frame Types 108 :widths: 1 1 4 109 :header-rows: 1 110 111 * - Name 112 - Value 113 - Short Description 114 115 * - |NAK| 116 - ``0x04`` 117 - Sent on error in previously received message. 118 119 * - |ACK| 120 - ``0x40`` 121 - Sent to acknowledge receival of |DATA| frame. 122 123 * - |DATA_SEQ| 124 - ``0x80`` 125 - Sent to transfer data. Sequenced. 126 127 * - |DATA_NSQ| 128 - ``0x00`` 129 - Same as |DATA_SEQ|, but does not need to be ACKed. 130 131Both |NAK|- and |ACK|-type frames are used to control flow of messages and 132thus do not carry a payload. |DATA_SEQ|- and |DATA_NSQ|-type frames on the 133other hand must carry a payload. The flow sequence and interaction of 134different frame types will be described in more depth in the next section. 135 136 137SSH Packet Protocol: Flow Sequence 138================================== 139 140Each exchange begins with |SYN|, followed by a |DATA_SEQ|- or 141|DATA_NSQ|-type frame, followed by its CRC, payload, and payload CRC. In 142case of a |DATA_NSQ|-type frame, the exchange is then finished. In case of a 143|DATA_SEQ|-type frame, the receiving party has to acknowledge receival of 144the frame by responding with a message containing an |ACK|-type frame with 145the same sequence ID of the |DATA| frame. In other words, the sequence ID of 146the |ACK| frame specifies the |DATA| frame to be acknowledged. In case of an 147error, e.g. an invalid CRC, the receiving party responds with a message 148containing an |NAK|-type frame. As the sequence ID of the previous data 149frame, for which an error is indicated via the |NAK| frame, cannot be relied 150upon, the sequence ID of the |NAK| frame should not be used and is set to 151zero. After receival of an |NAK| frame, the sending party should re-send all 152outstanding (non-ACKed) messages. 153 154Sequence IDs are not synchronized between the two parties, meaning that they 155are managed independently for each party. Identifying the messages 156corresponding to a single exchange thus relies on the sequence ID as well as 157the type of the message, and the context. Specifically, the sequence ID is 158used to associate an ``ACK`` with its ``DATA_SEQ``-type frame, but not 159``DATA_SEQ``- or ``DATA_NSQ``-type frames with other ``DATA``- type frames. 160 161An example exchange might look like this: 162 163:: 164 165 tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) ----------------------------- 166 rx: ------------------------------------- SYN FRAME(A) CRC(F) CRC(P) -- 167 168where both frames have the same sequence ID (``SEQ``). Here, ``FRAME(D)`` 169indicates a |DATA_SEQ|-type frame, ``FRAME(A)`` an ``ACK``-type frame, 170``CRC(F)`` the CRC over the previous frame, ``CRC(P)`` the CRC over the 171previous payload. In case of an error, the exchange would look like this: 172 173:: 174 175 tx: -- SYN FRAME(D) CRC(F) PAYLOAD CRC(P) ----------------------------- 176 rx: ------------------------------------- SYN FRAME(N) CRC(F) CRC(P) -- 177 178upon which the sender should re-send the message. ``FRAME(N)`` indicates an 179|NAK|-type frame. Note that the sequence ID of the |NAK|-type frame is fixed 180to zero. For |DATA_NSQ|-type frames, both exchanges are the same: 181 182:: 183 184 tx: -- SYN FRAME(DATA_NSQ) CRC(F) PAYLOAD CRC(P) ---------------------- 185 rx: ------------------------------------------------------------------- 186 187Here, an error can be detected, but not corrected or indicated to the 188sending party. These exchanges are symmetric, i.e. switching ``rx`` and 189``tx`` results again in a valid exchange. Currently, no longer exchanges are 190known. 191 192 193Commands: Requests, Responses, and Events 194========================================= 195 196Commands are sent as payload inside a data frame. Currently, this is the 197only known payload type of |DATA| frames, with a payload-type value of 198``0x80`` (:c:type:`SSH_PLD_TYPE_CMD <ssh_payload_type>`). 199 200The command-type payload (:c:type:`struct ssh_command <ssh_command>`) 201consists of an eight-byte command structure, followed by optional and 202variable length command data. The length of this optional data is derived 203from the frame payload length given in the corresponding frame, i.e. it is 204``frame.len - sizeof(struct ssh_command)``. The command struct contains the 205following fields, packed together and in order: 206 207.. flat-table:: SSH Command 208 :widths: 1 1 4 209 :header-rows: 1 210 211 * - Field 212 - Type 213 - Description 214 215 * - |TYPE| 216 - |u8| 217 - Type of the payload. For commands always ``0x80``. 218 219 * - |TC| 220 - |u8| 221 - Target category. 222 223 * - |TID| 224 - |u8| 225 - Target ID for commands/messages. 226 227 * - |SID| 228 - |u8| 229 - Source ID for commands/messages. 230 231 * - |IID| 232 - |u8| 233 - Instance ID. 234 235 * - |RQID| 236 - |u16| 237 - Request ID. 238 239 * - |CID| 240 - |u8| 241 - Command ID. 242 243The command struct and data, in general, does not contain any failure 244detection mechanism (e.g. CRCs), this is solely done on the frame level. 245 246Command-type payloads are used by the host to send commands and requests to 247the EC as well as by the EC to send responses and events back to the host. 248We differentiate between requests (sent by the host), responses (sent by the 249EC in response to a request), and events (sent by the EC without a preceding 250request). 251 252Commands and events are uniquely identified by their target category 253(``TC``) and command ID (``CID``). The target category specifies a general 254category for the command (e.g. system in general, vs. battery and AC, vs. 255temperature, and so on), while the command ID specifies the command inside 256that category. Only the combination of |TC| + |CID| is unique. Additionally, 257commands have an instance ID (``IID``), which is used to differentiate 258between different sub-devices. For example ``TC=3`` ``CID=1`` is a 259request to get the temperature on a thermal sensor, where |IID| specifies 260the respective sensor. If the instance ID is not used, it should be set to 261zero. If instance IDs are used, they, in general, start with a value of one, 262whereas zero may be used for instance independent queries, if applicable. A 263response to a request should have the same target category, command ID, and 264instance ID as the corresponding request. 265 266Responses are matched to their corresponding request via the request ID 267(``RQID``) field. This is a 16 bit wrapping counter similar to the sequence 268ID on the frames. Note that the sequence ID of the frames for a 269request-response pair does not match. Only the request ID has to match. 270Frame-protocol wise these are two separate exchanges, and may even be 271separated, e.g. by an event being sent after the request but before the 272response. Not all commands produce a response, and this is not detectable by 273|TC| + |CID|. It is the responsibility of the issuing party to wait for a 274response (or signal this to the communication framework, as is done in 275SAN/ACPI via the ``SNC`` flag). 276 277Events are identified by unique and reserved request IDs. These IDs should 278not be used by the host when sending a new request. They are used on the 279host to, first, detect events and, second, match them with a registered 280event handler. Request IDs for events are chosen by the host and directed to 281the EC when setting up and enabling an event source (via the 282enable-event-source request). The EC then uses the specified request ID for 283events sent from the respective source. Note that an event should still be 284identified by its target category, command ID, and, if applicable, instance 285ID, as a single event source can send multiple different event types. In 286general, however, a single target category should map to a single reserved 287event request ID. 288 289Furthermore, requests, responses, and events have an associated target ID 290(``TID``) and source ID (``SID``). These two fields indicate where a message 291originates from (``SID``) and what the intended target of the message is 292(``TID``). Note that a response to a specific request therefore has the source 293and target IDs swapped when compared to the original request (i.e. the request 294target is the response source and the request source is the response target). 295See (:c:type:`enum ssh_request_id <ssh_request_id>`) for possible values of 296both. 297 298Note that, even though requests and events should be uniquely identifiable by 299target category and command ID alone, the EC may require specific target ID and 300instance ID values to accept a command. A command that is accepted for 301``TID=1``, for example, may not be accepted for ``TID=2`` and vice versa. While 302this may not always hold in reality, you can think of different target/source 303IDs indicating different physical ECs with potentially different feature sets. 304 305 306Limitations and Observations 307============================ 308 309The protocol can, in theory, handle up to ``U8_MAX`` frames in parallel, 310with up to ``U16_MAX`` pending requests (neglecting request IDs reserved for 311events). In practice, however, this is more limited. From our testing 312(although via a python and thus a user-space program), it seems that the EC 313can handle up to four requests (mostly) reliably in parallel at a certain 314time. With five or more requests in parallel, consistent discarding of 315commands (ACKed frame but no command response) has been observed. For five 316simultaneous commands, this reproducibly resulted in one command being 317dropped and four commands being handled. 318 319However, it has also been noted that, even with three requests in parallel, 320occasional frame drops happen. Apart from this, with a limit of three 321pending requests, no dropped commands (i.e. command being dropped but frame 322carrying command being ACKed) have been observed. In any case, frames (and 323possibly also commands) should be re-sent by the host if a certain timeout 324is exceeded. This is done by the EC for frames with a timeout of one second, 325up to two re-tries (i.e. three transmissions in total). The limit of 326re-tries also applies to received NAKs, and, in a worst case scenario, can 327lead to entire messages being dropped. 328 329While this also seems to work fine for pending data frames as long as no 330transmission failures occur, implementation and handling of these seems to 331depend on the assumption that there is only one non-acknowledged data frame. 332In particular, the detection of repeated frames relies on the last sequence 333number. This means that, if a frame that has been successfully received by 334the EC is sent again, e.g. due to the host not receiving an |ACK|, the EC 335will only detect this if it has the sequence ID of the last frame received 336by the EC. As an example: Sending two frames with ``SEQ=0`` and ``SEQ=1`` 337followed by a repetition of ``SEQ=0`` will not detect the second ``SEQ=0`` 338frame as such, and thus execute the command in this frame each time it has 339been received, i.e. twice in this example. Sending ``SEQ=0``, ``SEQ=1`` and 340then repeating ``SEQ=1`` will detect the second ``SEQ=1`` as repetition of 341the first one and ignore it, thus executing the contained command only once. 342 343In conclusion, this suggests a limit of at most one pending un-ACKed frame 344(per party, effectively leading to synchronous communication regarding 345frames) and at most three pending commands. The limit to synchronous frame 346transfers seems to be consistent with behavior observed on Windows. 347