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 "pci_handler.hpp"
18
19 #include "data.hpp"
20
21 #include <fcntl.h>
22 #include <linux/aspeed-p2a-ctrl.h>
23
24 #include <cstdint>
25 #include <cstring>
26 #include <string>
27 #include <vector>
28
29 namespace ipmi_flash
30 {
31
32 const std::string PciDataHandler::p2aControlPath = "/dev/aspeed-p2a-ctrl";
33
open()34 bool PciDataHandler::open()
35 {
36 mappedFd = sys->open(p2aControlPath.c_str(), O_RDWR);
37 if (mappedFd == -1)
38 {
39 return false;
40 }
41
42 struct aspeed_p2a_ctrl_mapping map;
43 map.addr = regionAddress;
44 map.length = memoryRegionSize;
45 map.flags = ASPEED_P2A_CTRL_READWRITE;
46
47 if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_SET_WINDOW, &map))
48 {
49 sys->close(mappedFd);
50 mappedFd = -1;
51
52 return false;
53 }
54
55 if (sys->ioctl(mappedFd, ASPEED_P2A_CTRL_IOCTL_GET_MEMORY_CONFIG, &map))
56 {
57 sys->close(mappedFd);
58 mappedFd = -1;
59
60 return false;
61 }
62
63 /* The length of the region reserved is reported, and it's important
64 * because the offset + memory region could be beyond that reserved
65 * region.
66 */
67 std::uint64_t offset = regionAddress - map.addr;
68
69 mapped = reinterpret_cast<std::uint8_t*>(
70 mmap(0, memoryRegionSize, PROT_READ, MAP_SHARED, mappedFd, offset));
71 if (mapped == MAP_FAILED)
72 {
73 sys->close(mappedFd);
74 mappedFd = -1;
75 mapped = nullptr;
76
77 return false;
78 }
79
80 return true;
81 }
82
close()83 bool PciDataHandler::close()
84 {
85 /* TODO: Turn off the P2A bridge and region to disable host-side access.
86 */
87 if (mapped)
88 {
89 sys->munmap(mapped, memoryRegionSize);
90 mapped = nullptr;
91 }
92
93 if (mappedFd != -1)
94 {
95 sys->close(mappedFd);
96 mappedFd = -1;
97 }
98
99 return true;
100 }
101
copyFrom(std::uint32_t length)102 std::vector<std::uint8_t> PciDataHandler::copyFrom(std::uint32_t length)
103 {
104 std::vector<std::uint8_t> results(length);
105 std::memcpy(results.data(), mapped, length);
106
107 return results;
108 }
109
writeMeta(const std::vector<std::uint8_t> &)110 bool PciDataHandler::writeMeta(const std::vector<std::uint8_t>&)
111 {
112 /* PCI handler doesn't require configuration write, only read. */
113 return false;
114 }
115
readMeta()116 std::vector<std::uint8_t> PciDataHandler::readMeta()
117 {
118 /* PCI handler does require returning a configuration from read. */
119 struct PciConfigResponse reply;
120 reply.address = regionAddress;
121
122 std::vector<std::uint8_t> bytes;
123 bytes.resize(sizeof(reply));
124 std::memcpy(bytes.data(), &reply, sizeof(reply));
125
126 return bytes;
127 }
128
129 } // namespace ipmi_flash
130