blob: ea3a9329f50e0cbe8b8ef7b179558ca4af944b61 [file] [log] [blame]
Tom Josephf8329ac2019-04-11 22:13:22 +05301#pragma once
2
3#include <stdint.h>
4#include <unistd.h>
5
6#include <filesystem>
7
8#include "libpldm/base.h"
9#include "libpldm/file_io.h"
10
11namespace pldm
12{
13
14namespace responder
15{
16
17namespace utils
18{
19
20/** @struct CustomFD
21 *
22 * RAII wrapper for file descriptor.
23 */
24struct CustomFD
25{
26 CustomFD(const CustomFD&) = delete;
27 CustomFD& operator=(const CustomFD&) = delete;
28 CustomFD(CustomFD&&) = delete;
29 CustomFD& operator=(CustomFD&&) = delete;
30
31 CustomFD(int fd) : fd(fd)
32 {
33 }
34
35 ~CustomFD()
36 {
37 if (fd >= 0)
38 {
39 close(fd);
40 }
41 }
42
43 int operator()() const
44 {
45 return fd;
46 }
47
48 private:
49 int fd = -1;
50};
51
52} // namespace utils
53
54namespace dma
55{
56
Tom Josephf8329ac2019-04-11 22:13:22 +053057// The minimum data size of dma transfer in bytes
58constexpr uint32_t minSize = 16;
59
60// 16MB - 4096B (16773120 bytes) is the maximum data size of DMA transfer
61constexpr size_t maxSize = (16 * 1024 * 1024) - 4096;
62
Tom Joseph55306762019-05-02 09:11:26 +053063namespace fs = std::filesystem;
64
65/**
66 * @class DMA
Tom Josephf8329ac2019-04-11 22:13:22 +053067 *
Tom Joseph55306762019-05-02 09:11:26 +053068 * Expose API to initiate transfer of data by DMA
Eddie James3b02e272019-04-22 20:13:55 +000069 *
Tom Joseph55306762019-05-02 09:11:26 +053070 * This class only exposes the public API transferDataHost to transfer data
71 * between BMC and host using DMA. This allows for mocking the transferDataHost
72 * for unit testing purposes.
Tom Josephf8329ac2019-04-11 22:13:22 +053073 */
Tom Joseph55306762019-05-02 09:11:26 +053074class DMA
75{
76 public:
77 /** @brief API to transfer data between BMC and host using DMA
78 *
79 * @param[in] path - pathname of the file to transfer data from or to
80 * @param[in] offset - offset in the file
81 * @param[in] length - length of the data to transfer
82 * @param[in] address - DMA address on the host
83 * @param[in] upstream - indicates direction of the transfer; true indicates
84 * transfer to the host
85 *
86 * @return returns 0 on success, negative errno on failure
87 */
88 int transferDataHost(const fs::path& path, uint32_t offset, uint32_t length,
89 uint64_t address, bool upstream);
90};
Tom Josephf8329ac2019-04-11 22:13:22 +053091
Eddie James3b02e272019-04-22 20:13:55 +000092/** @brief Transfer the data between BMC and host using DMA.
93 *
94 * There is a max size for each DMA operation, transferAll API abstracts this
95 * and the requested length is broken down into multiple DMA operations if the
96 * length exceed max size.
97 *
Tom Joseph55306762019-05-02 09:11:26 +053098 * @tparam[in] T - DMA interface type
99 * @param[in] intf - interface passed to invoke DMA transfer
Eddie James3b02e272019-04-22 20:13:55 +0000100 * @param[in] command - PLDM command
101 * @param[in] path - pathname of the file to transfer data from or to
102 * @param[in] offset - offset in the file
103 * @param[in] length - length of the data to transfer
104 * @param[in] address - DMA address on the host
105 * @param[in] upstream - indicates direction of the transfer; true indicates
106 * transfer to the host
107 * @param[out] response - response message location
108 */
Tom Joseph55306762019-05-02 09:11:26 +0530109
110template <class DMAInterface>
111void transferAll(DMAInterface* intf, uint8_t command, fs::path& path,
112 uint32_t offset, uint32_t length, uint64_t address,
113 bool upstream, pldm_msg* response)
114{
115 uint32_t origLength = length;
116
117 while (length > dma::maxSize)
118 {
119 auto rc = intf->transferDataHost(path, offset, dma::maxSize, address,
120 upstream);
121 if (rc < 0)
122 {
123 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, response);
124 return;
125 }
126
127 offset += dma::maxSize;
128 length -= dma::maxSize;
129 address += dma::maxSize;
130 }
131
132 auto rc = intf->transferDataHost(path, offset, length, address, upstream);
133 if (rc < 0)
134 {
135 encode_rw_file_memory_resp(0, command, PLDM_ERROR, 0, response);
136 return;
137 }
138
139 encode_rw_file_memory_resp(0, command, PLDM_SUCCESS, origLength, response);
140 return;
141}
142
143} // namespace dma
Eddie James3b02e272019-04-22 20:13:55 +0000144
Tom Josephf8329ac2019-04-11 22:13:22 +0530145/** @brief Handler for readFileIntoMemory command
146 *
147 * @param[in] request - pointer to PLDM request payload
148 * @param[in] payloadLength - length of the message payload
149 * @param[out] response - response message location
150 */
151void readFileIntoMemory(const uint8_t* request, size_t payloadLength,
152 pldm_msg* response);
153
Eddie James3b02e272019-04-22 20:13:55 +0000154/** @brief Handler for writeFileIntoMemory command
155 *
156 * @param[in] request - pointer to PLDM request payload
157 * @param[in] payloadLength - length of the message payload
158 * @param[out] response - response message location
159 */
160void writeFileFromMemory(const uint8_t* request, size_t payloadLength,
161 pldm_msg* response);
162
Tom Josephf8329ac2019-04-11 22:13:22 +0530163} // namespace responder
164} // namespace pldm