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 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 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 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 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 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