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_aspeed.hpp" 18 19 #include "mapper_errors.hpp" 20 #include "window_hw_interface.hpp" 21 22 #include <fcntl.h> 23 #include <linux/aspeed-lpc-ctrl.h> 24 #include <linux/kernel.h> 25 26 #include <cerrno> 27 #include <cstdint> 28 #include <cstring> 29 #include <memory> 30 #include <string> 31 #include <utility> 32 33 namespace ipmi_flash 34 { 35 36 const std::string LpcMapperAspeed::lpcControlPath = "/dev/aspeed-lpc-ctrl"; 37 38 std::unique_ptr<HardwareMapperInterface> 39 LpcMapperAspeed::createAspeedMapper(std::uint32_t regionAddress, 40 std::size_t regionSize) 41 { 42 /* NOTE: considered using a joint factory to create one or the other, for 43 * now, separate factories. 44 */ 45 return std::make_unique<LpcMapperAspeed>(regionAddress, regionSize); 46 } 47 48 void LpcMapperAspeed::close() 49 { 50 if (mappedRegion) 51 { 52 sys->munmap(mappedRegion, regionSize); 53 mappedRegion = nullptr; 54 } 55 56 if (mappedFd != -1) 57 { 58 sys->close(mappedFd); 59 mappedFd = -1; 60 } 61 } 62 63 WindowMapResult LpcMapperAspeed::mapWindow(std::uint32_t address, 64 std::uint32_t length) 65 { 66 WindowMapResult result = {}; 67 static const std::uint32_t MASK_64K = 0xFFFFU; 68 const std::uint32_t offset = address & MASK_64K; 69 70 if (offset + length > regionSize) 71 { 72 std::fprintf(stderr, 73 "requested window size %" PRIu32 ", offset %#" PRIx32 74 " is too large for mem region" 75 " of size %zu\n", 76 length, offset, regionSize); 77 78 result.response = EFBIG; 79 result.windowSize = regionSize - offset; 80 return result; 81 } 82 83 struct aspeed_lpc_ctrl_mapping map = { 84 .window_type = ASPEED_LPC_CTRL_WINDOW_MEMORY, 85 .window_id = 0, 86 .flags = 0, 87 .addr = address & ~MASK_64K, 88 .offset = 0, 89 .size = __ALIGN_KERNEL_MASK(offset + length, MASK_64K), 90 }; 91 92 std::fprintf(stderr, 93 "requesting Aspeed LPC window at %#" PRIx32 " of size %" PRIu32 94 "\n", 95 map.addr, map.size); 96 97 const auto lpcControlFd = sys->open(lpcControlPath.c_str(), O_RDWR); 98 if (lpcControlFd == -1) 99 { 100 std::fprintf(stderr, 101 "cannot open Aspeed LPC kernel control dev \"%s\"\n", 102 lpcControlPath.c_str()); 103 104 result.response = EINVAL; 105 return result; 106 } 107 108 if (sys->ioctl(lpcControlFd, ASPEED_LPC_CTRL_IOCTL_MAP, &map) == -1) 109 { 110 std::fprintf(stderr, "Failed to ioctl Aspeed LPC map with error %s\n", 111 std::strerror(errno)); 112 sys->close(lpcControlFd); 113 114 result.response = EINVAL; 115 return result; 116 } 117 118 sys->close(lpcControlFd); 119 120 result.response = 0; 121 result.windowOffset = offset; 122 result.windowSize = length; 123 return result; 124 } 125 126 MemorySet LpcMapperAspeed::open() 127 { 128 if (mapRegion()) 129 { 130 MemorySet output; 131 output.mappedFd = mappedFd; 132 output.mapped = mappedRegion; 133 return output; 134 } 135 136 throw MapperException("Unable to memory-map region"); 137 } 138 139 bool LpcMapperAspeed::mapRegion() 140 { 141 /* Open the file to map. */ 142 mappedFd = sys->open(lpcControlPath.c_str(), O_RDONLY | O_SYNC); 143 if (mappedFd == -1) 144 { 145 std::fprintf(stderr, "ipmiflash: unable to open %s\n", 146 lpcControlPath.c_str()); 147 return false; 148 } 149 150 mappedRegion = reinterpret_cast<uint8_t*>( 151 sys->mmap(0, regionSize, PROT_READ, MAP_SHARED, mappedFd, 0)); 152 153 if (mappedRegion == MAP_FAILED) 154 { 155 sys->close(mappedFd); 156 mappedFd = -1; 157 std::fprintf(stderr, "Mmap failure: '%s'\n", std::strerror(errno)); 158 return false; 159 } 160 161 /* TOOD: There is no close() method here, to close mappedFd, or mappedRegion 162 * -- therefore, a good next step will be to evaluate whether or not the 163 * other pieces should go here... 164 */ 165 return true; 166 } 167 168 } // namespace ipmi_flash 169