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
VSoCSharedMemoryImpl(const std::map<std::string,size_t> & name_to_region_idx,const std::vector<Region> & regions,const std::string & path)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
SharedMemFD() const73 const cvd::SharedFD &VSoCSharedMemoryImpl::SharedMemFD() const {
74 return shared_mem_fd_;
75 }
76
Regions() const77 const std::vector<VSoCSharedMemory::Region> &VSoCSharedMemoryImpl::Regions()
78 const {
79 return region_data_;
80 }
81
GetEventFdPairForRegion(const std::string & region_name,cvd::SharedFD * guest_to_host,cvd::SharedFD * host_to_guest) const82 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
New(const std::string & path)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