Support IPMI Serial Transport

Support IPMI Serial interface (basic mode) based on Sec 14,
IPMI 2.0 spec. Serial transport tested with meta-evb-arm
platform with socat and ipmitool.

HW transport can be selected by meson configure flasg.

Tested:

1. socat -x pty,raw,echo=0,link=/tmp/ttyHOST2BMC tcp:localhost:5066
2. ipmitool -I serial-basic -D /tmp/ttyHOST2BMC:115200 mc info

    Device ID                 : 0
    Device Revision           : 0
    Firmware Revision         : 2.17
    IPMI Version              : 2.0
    Manufacturer ID           : 0
    Manufacturer Name         : Unknown
    Product ID                : 0 (0x0000)
    Product Name              : Unknown (0x0)
    Device Available          : no
    Provides Device SDRs      : no
    Additional Device Support :
    Aux Firmware Rev Info     :
        0x00
        0x00
        0x00
        0x00

Change-Id: I2a56390022fce7a974ed75ed6a72ad3fffed9bb6
Signed-off-by: John Chung <john.chung@arm.com>
diff --git a/transport/serialbridge/serialcmd.hpp b/transport/serialbridge/serialcmd.hpp
new file mode 100644
index 0000000..985921c
--- /dev/null
+++ b/transport/serialbridge/serialcmd.hpp
@@ -0,0 +1,64 @@
+#pragma once
+#include <sdbusplus/bus.hpp>
+#include <sdbusplus/message.hpp>
+#include <sdbusplus/slot.hpp>
+#include <stdplus/fd/intf.hpp>
+
+namespace serialbridge
+{
+
+static constexpr auto bmStart = 0xA0;
+static constexpr auto bmStop = 0xA5;
+static constexpr auto bmHandshake = 0xA6;
+static constexpr auto bmEscape = 0xAA;
+
+static constexpr auto ipmiSerialConnectionHeaderLength = 3;
+static constexpr auto ipmiSerialChecksumSize = 1;
+static constexpr auto ipmiSerialMaxBufferSize = 256;
+
+/**
+ * @brief IPMI Serial Message Structure
+ */
+struct IpmiSerialHeader
+{
+    uint8_t rsAddr;
+    uint8_t rsNetFnLUN;
+    uint8_t checksum1;
+    uint8_t rqAddr;
+    uint8_t rqSeqLUN;
+    uint8_t cmd;
+} __attribute__((packed));
+
+class SerialChannel
+{
+  public:
+    static constexpr uint8_t netFnShift = 2;
+    static constexpr uint8_t lunMask = (1 << netFnShift) - 1;
+
+    SerialChannel(bool debug) : verbose(debug), msgState(MsgState::msgIdle) {};
+
+    int write(stdplus::Fd& uart, uint8_t rsAddr, uint8_t rqAddr, uint8_t seq,
+              sdbusplus::message_t&& m);
+    void read(stdplus::Fd& serial, sdbusplus::bus_t& bus,
+              sdbusplus::slot_t& outstanding);
+    uint8_t calculateChecksum(std::span<uint8_t> data);
+    uint8_t getUnescapedCharacter(uint8_t c);
+    int consumeIpmiSerialPacket(std::span<uint8_t>& escapedDataBytes,
+                                std::vector<uint8_t>& unescapedDataBytes);
+    uint8_t processEscapedCharacter(std::vector<uint8_t>& buffer,
+                                    const std::vector<uint8_t>& data);
+
+  private:
+    bool verbose;
+    enum class MsgState
+    {
+        msgIdle = 0,
+        msgInProgress,
+        msgInEscape,
+    };
+    MsgState msgState;
+    std::vector<uint8_t> requestBuffer;
+    std::vector<uint8_t> responseBuffer;
+};
+
+} // namespace serialbridge