1 /* 2 * Copyright (C) 2017 The Android Open Source Project 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 #include "host/commands/ivserver/vsocsharedmem.h" 17 18 #include <errno.h> 19 #include <fcntl.h> 20 #include <stdio.h> 21 #include <stdlib.h> 22 #include <string.h> 23 #include <sys/eventfd.h> 24 #include <sys/mman.h> 25 #include <sys/stat.h> 26 #include <unistd.h> 27 #include <algorithm> 28 #include <tuple> 29 30 #include <glog/logging.h> 31 32 #include "common/vsoc/lib/vsoc_memory.h" 33 #include "uapi/vsoc_shm.h" 34 35 namespace ivserver { 36 namespace { 37 38 class VSoCSharedMemoryImpl : public VSoCSharedMemory { 39 public: 40 VSoCSharedMemoryImpl(const std::map<std::string, size_t> &name_to_region_idx, 41 const std::vector<Region> ®ions, 42 const std::string &path); 43 44 bool GetEventFdPairForRegion(const std::string ®ion_name, 45 cvd::SharedFD *guest_to_host, 46 cvd::SharedFD *host_to_guest) const override; 47 48 const cvd::SharedFD &SharedMemFD() const override; 49 50 const std::vector<Region> &Regions() const override; 51 52 private: 53 void CreateLayout(); 54 55 cvd::SharedFD shared_mem_fd_; 56 const std::map<std::string, size_t> region_name_to_index_; 57 const std::vector<Region> region_data_; 58 59 VSoCSharedMemoryImpl(const VSoCSharedMemoryImpl &) = delete; 60 VSoCSharedMemoryImpl &operator=(const VSoCSharedMemoryImpl &other) = delete; 61 }; 62 63 VSoCSharedMemoryImpl::VSoCSharedMemoryImpl( 64 const std::map<std::string, size_t> &name_to_region_idx, 65 const std::vector<Region> ®ions, const std::string &path) 66 : shared_mem_fd_(cvd::SharedFD::Open(path.c_str(), O_RDWR)), 67 region_name_to_index_{name_to_region_idx}, 68 region_data_{regions} { 69 LOG_IF(FATAL, !shared_mem_fd_->IsOpen()) 70 << "Error in creating shared_memory file: " << shared_mem_fd_->StrError(); 71 } 72 73 const cvd::SharedFD &VSoCSharedMemoryImpl::SharedMemFD() const { 74 return shared_mem_fd_; 75 } 76 77 const std::vector<VSoCSharedMemory::Region> &VSoCSharedMemoryImpl::Regions() 78 const { 79 return region_data_; 80 } 81 82 bool VSoCSharedMemoryImpl::GetEventFdPairForRegion( 83 const std::string ®ion_name, cvd::SharedFD *guest_to_host, 84 cvd::SharedFD *host_to_guest) const { 85 auto it = region_name_to_index_.find(region_name); 86 if (it == region_name_to_index_.end()) return false; 87 88 *guest_to_host = region_data_[it->second].host_fd; 89 *host_to_guest = region_data_[it->second].guest_fd; 90 return true; 91 } 92 93 } // anonymous namespace 94 95 std::unique_ptr<VSoCSharedMemory> VSoCSharedMemory::New( 96 const std::string &path) { 97 auto device_layout = vsoc::VSoCMemoryLayout::Get(); 98 99 std::map<std::string, size_t> name_to_region_idx; 100 std::vector<Region> regions; 101 regions.reserve(device_layout->GetRegions().size()); 102 103 for (auto region_spec : device_layout->GetRegions()) { 104 auto device_name = region_spec->region_name(); 105 106 // Create one pair of eventfds for this region. Note that the guest to host 107 // eventfd is non-blocking, whereas the host to guest eventfd is blocking. 108 // This is in anticipation of blocking semantics for the host side locks. 109 auto host_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK); 110 if (!host_fd->IsOpen()) { 111 LOG(ERROR) << "Failed to create host eventfd for " << device_name << ": " 112 << host_fd->StrError(); 113 return nullptr; 114 } 115 auto guest_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK); 116 if (!guest_fd->IsOpen()) { 117 LOG(ERROR) << "Failed to create guest eventfd for " << device_name << ": " 118 << guest_fd->StrError(); 119 return nullptr; 120 } 121 122 auto region_idx = regions.size(); 123 name_to_region_idx[device_name] = region_idx; 124 regions.emplace_back(device_name, host_fd, guest_fd); 125 } 126 127 return std::unique_ptr<VSoCSharedMemory>( 128 new VSoCSharedMemoryImpl(name_to_region_idx, regions, path)); 129 } 130 131 } // namespace ivserver 132