1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "lpc_handler.hpp"
18 
19 #include "mapper_errors.hpp"
20 
21 #include <cstdint>
22 #include <cstdio>
23 #include <cstring>
24 #include <vector>
25 
26 namespace ipmi_flash
27 {
28 
29 bool LpcDataHandler::setInitializedAndReturn(bool value)
30 {
31     if (value)
32     {
33         try
34         {
35             /* Try really opening the map. */
36             memory = mapper->open();
37         }
38         catch (const MapperException& e)
39         {
40             std::fprintf(stderr, "received mapper exception: %s\n", e.what());
41             return false;
42         }
43     }
44 
45     initialized = value;
46     return value;
47 }
48 
49 bool LpcDataHandler::open()
50 {
51     /* For the ASPEED LPC CTRL driver, the ioctl is required to set up the
52      * window, with information from writeMeta() below.
53      */
54     return true;
55 }
56 
57 bool LpcDataHandler::close()
58 {
59     mapper->close();
60 
61     return setInitializedAndReturn(false);
62 }
63 
64 std::vector<std::uint8_t> LpcDataHandler::copyFrom(std::uint32_t length)
65 {
66     /* TODO: implement this -- in an earlier and different version of this that
67      * didn't use BLOBs, the region was memory-mapped and the writes to the data
68      * were just done directly from the memory-mapped region instead of a
69      * copyFrom() first call.  The idea with this change is that we may not be
70      * able to get a memory-mapped handle from the driver from which to
71      * automatically read data, but rather must perform some ioctl or other
72      * access to get the data from the driver.
73      */
74     if (!initialized)
75     {
76         /* TODO: Consider designing some exceptions we can catch for when there
77          * is an error.
78          */
79         return {};
80     }
81 
82     std::vector<std::uint8_t> results(length);
83     std::memcpy(results.data(), memory.mapped + mappingResult.windowOffset,
84                 length);
85 
86     return results;
87 }
88 
89 bool LpcDataHandler::writeMeta(const std::vector<std::uint8_t>& configuration)
90 {
91     struct LpcRegion lpcRegion;
92 
93     if (configuration.size() != sizeof(lpcRegion))
94     {
95         return false;
96     }
97 
98     std::memcpy(&lpcRegion, configuration.data(), configuration.size());
99 
100     /* TODO: LpcRegion sanity checking. */
101     mappingResult = mapper->mapWindow(lpcRegion.address, lpcRegion.length);
102     if (mappingResult.response != 0)
103     {
104         std::fprintf(stderr, "mappingResult.response %u\n",
105                      mappingResult.response);
106         /* Failed to map region. */
107         return false;
108     }
109 
110     return setInitializedAndReturn(true);
111 }
112 
113 std::vector<std::uint8_t> LpcDataHandler::readMeta()
114 {
115     /* Return the MemoryResult structure packed. */
116     std::vector<std::uint8_t> output(
117         sizeof(std::uint8_t) + sizeof(std::uint32_t) + sizeof(std::uint32_t));
118 
119     int index = 0;
120     std::memcpy(&output[index], &mappingResult.response,
121                 sizeof(mappingResult.response));
122 
123     index += sizeof(mappingResult.response);
124     std::memcpy(&output[index], &mappingResult.windowOffset,
125                 sizeof(mappingResult.windowOffset));
126 
127     index += sizeof(mappingResult.windowOffset);
128     std::memcpy(&output[index], &mappingResult.windowSize,
129                 sizeof(mappingResult.windowSize));
130 
131     return output;
132 }
133 
134 } // namespace ipmi_flash
135