blob: 8f535081330084438146e6227cbc3d88ffda9efb [file] [log] [blame]
Greg Hartmane08d8b22017-08-08 16:44:29 -07001/*
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 */
Greg Hartman86b114a2017-11-03 21:04:14 -070016#include "host/vsoc/lib/region_control.h"
Greg Hartmanefe487a2017-11-10 20:39:06 -080017#include "common/vsoc/lib/region_view.h"
Greg Hartmane08d8b22017-08-08 16:44:29 -070018
19#define LOG_TAG "vsoc: region_host"
20
21#include <stdio.h>
22#include <string.h>
23#include <sys/mman.h>
24#include <sys/socket.h>
25#include <sys/syscall.h>
26#include <sys/types.h>
27#include <unistd.h>
28
Greg Hartmanefe487a2017-11-10 20:39:06 -080029#include <iomanip>
Greg Hartmane08d8b22017-08-08 16:44:29 -070030#include <sstream>
31#include <thread>
32#include <vector>
33
Greg Hartmanefe487a2017-11-10 20:39:06 -080034#include <gflags/gflags.h>
Greg Hartmane08d8b22017-08-08 16:44:29 -070035#include <glog/logging.h>
36
37#include "common/libs/fs/shared_fd.h"
38#include "common/libs/fs/shared_select.h"
39
40using avd::SharedFD;
41
Greg Hartmanefe487a2017-11-10 20:39:06 -080042DEFINE_int32(instance, 1, "Instance number. Must be unique.");
43DEFINE_string(vsoc_run_dir, "/var/run/cvd-",
44 "Path to the directory holding vsoc resources");
45DEFINE_string(vsoc_shm_client_sock, "ivshmem_socket_client",
46 "Name of the VSoC client socket");
47
Greg Hartmane08d8b22017-08-08 16:44:29 -070048namespace {
Greg Hartmanefe487a2017-11-10 20:39:06 -080049
Greg Hartmane08d8b22017-08-08 16:44:29 -070050class HostRegionControl : public vsoc::RegionControl {
51 public:
52 HostRegionControl(const char* region_name,
53 const SharedFD& incoming_interrupt_fd,
54 const SharedFD& outgoing_interrupt_fd,
55 const SharedFD& shared_memory_fd)
56 : region_name_{region_name},
57 incoming_interrupt_fd_{incoming_interrupt_fd},
58 outgoing_interrupt_fd_{outgoing_interrupt_fd},
59 shared_memory_fd_{shared_memory_fd} {}
60
61 int CreateFdScopedPermission(const char* managed_region_name,
62 vsoc_reg_off_t owner_offset, uint32_t owned_val,
63 vsoc_reg_off_t begin_offset,
64 vsoc_reg_off_t end_offset) override {
65 return -1;
66 }
67
68 bool InitializeRegion();
69
70 virtual bool InterruptPeer() override {
71 uint64_t one = 1;
72 ssize_t rval = outgoing_interrupt_fd_->Write(&one, sizeof(one));
73 if (rval != sizeof(one)) {
74 LOG(FATAL) << __FUNCTION__ << ": rval (" << rval << ") != sizeof(one))";
75 return false;
76 }
77 return true;
78 }
79
80 // Wake the local signal table scanner. Primarily used during shutdown
81 virtual void InterruptSelf() override {
82 uint64_t one = 1;
83 ssize_t rval = incoming_interrupt_fd_->Write(&one, sizeof(one));
84 if (rval != sizeof(one)) {
85 LOG(FATAL) << __FUNCTION__ << ": rval (" << rval << ") != sizeof(one))";
86 }
87 }
88
89 virtual void WaitForInterrupt() override {
90 // Check then act isn't a problem here: the other side does
91 // the following things in exactly this order:
92 // 1. exchanges 1 with interrupt_signalled
93 // 2. if interrupt_signalled was 0 it increments the eventfd
94 // eventfd increments are persistent, so if interrupt_signalled was set
95 // back to 1 while we are going to sleep the sleep will return
96 // immediately.
97 uint64_t missed{};
98 avd::SharedFDSet readset;
99 readset.Set(incoming_interrupt_fd_);
100 avd::Select(&readset, NULL, NULL, NULL);
101 ssize_t rval = incoming_interrupt_fd_->Read(&missed, sizeof(missed));
102 if (rval != sizeof(missed)) {
103 LOG(FATAL) << __FUNCTION__ << ": rval (" << rval
104 << ") != sizeof(missed))";
105 }
106 if (!missed) {
107 LOG(FATAL) << __FUNCTION__ << ": woke with 0 interrupts";
108 }
109 }
110
111 virtual void* Map() override {
112 if (region_base_) {
113 return region_base_;
114 }
115 // Now actually map the region
116 region_base_ =
117 shared_memory_fd_->Mmap(0, region_size(), PROT_READ | PROT_WRITE,
118 MAP_SHARED, region_desc_.region_begin_offset);
119 if (region_base_ == MAP_FAILED) {
120 LOG(FATAL) << "mmap failed for offset "
121 << region_desc_.region_begin_offset << " ("
122 << shared_memory_fd_->StrError() << ")";
123 region_base_ = nullptr;
124 }
125 return region_base_;
126 }
127
128 protected:
129 const char* region_name_{};
130 avd::SharedFD incoming_interrupt_fd_;
131 avd::SharedFD outgoing_interrupt_fd_;
132 avd::SharedFD shared_memory_fd_;
133};
134
135// Default path to the ivshmem_server socket. This can vary when we're
136// launching multiple AVDs.
Greg Hartmane08d8b22017-08-08 16:44:29 -0700137constexpr int kMaxSupportedProtocolVersion = 0;
138
139bool HostRegionControl::InitializeRegion() {
140 size_t region_name_len = strlen(region_name_);
141 if (region_name_len >= sizeof(vsoc_device_name)) {
142 LOG(FATAL) << "Region name length (" << region_name_len << ") not < "
143 << sizeof(vsoc_device_name);
144 return false;
145 }
146 vsoc_shm_layout_descriptor layout;
147 ssize_t rval = shared_memory_fd_->Pread(&layout, sizeof(layout), 0);
148 if (rval != sizeof(layout)) {
149 LOG(FATAL) << "Unable to read layout, rval=" << rval << " ("
150 << shared_memory_fd_->StrError() << ")";
151 return false;
152 }
153 if (layout.major_version != CURRENT_VSOC_LAYOUT_MAJOR_VERSION) {
154 LOG(FATAL) << "Incompatible major version: saw " << layout.major_version
155 << " wanted " << CURRENT_VSOC_LAYOUT_MAJOR_VERSION;
156 }
157 std::vector<vsoc_device_region> descriptors;
158 descriptors.resize(layout.region_count);
159 ssize_t wanted = sizeof(vsoc_device_region) * layout.region_count;
160 rval = shared_memory_fd_->Pread(descriptors.data(), wanted,
161 layout.vsoc_region_desc_offset);
162 if (rval != wanted) {
163 LOG(FATAL) << "Unable to read region descriptors, rval=" << rval << " ("
164 << shared_memory_fd_->StrError() << ")";
165 return false;
166 }
167 for (const auto& desc : descriptors) {
168 if (!strcmp(region_name_, desc.device_name)) {
169 region_desc_ = desc;
170 return true;
171 }
172 }
173
174 std::ostringstream buf;
175 for (const auto& desc : descriptors) {
176 buf << " " << desc.device_name;
177 }
178 LOG(FATAL) << "Region name of " << region_name_
179 << " not found among:" << buf.str();
180 return false;
181}
182} // namespace
183
Greg Hartmanefe487a2017-11-10 20:39:06 -0800184std::string vsoc::GetShmClientSocketPath() {
185 std::ostringstream stream;
186 stream << FLAGS_vsoc_run_dir << std::setfill('0') << std::setw(2)
187 << FLAGS_instance << "/" << FLAGS_vsoc_shm_client_sock;
188 return stream.str();
189}
190
Greg Hartmane08d8b22017-08-08 16:44:29 -0700191std::shared_ptr<vsoc::RegionControl> vsoc::RegionControl::Open(
192 const char* region_name, const char* domain) {
193 AutoFreeBuffer msg;
Greg Hartmanefe487a2017-11-10 20:39:06 -0800194 std::string owned_domain;
Greg Hartmane08d8b22017-08-08 16:44:29 -0700195
196 if (!domain) {
Greg Hartmanefe487a2017-11-10 20:39:06 -0800197 owned_domain = GetShmClientSocketPath();
198 domain = owned_domain.c_str();
Greg Hartmane08d8b22017-08-08 16:44:29 -0700199 }
200 SharedFD region_server =
201 SharedFD::SocketLocalClient(domain, false, SOCK_STREAM);
202 if (!region_server->IsOpen()) {
203 LOG(FATAL) << "Could not contact ivshmem_server ("
204 << region_server->StrError() << ")";
205 return nullptr;
206 }
207
208 // Check server protocol version.
209 uint32_t protocol_version;
210 ssize_t bytes = region_server->Recv(&protocol_version,
211 sizeof(protocol_version), MSG_NOSIGNAL);
212 if (bytes != sizeof(protocol_version)) {
213 LOG(FATAL) << "Failed to recv protocol version; res=" << bytes << " ("
214 << region_server->StrError() << ")";
215 return nullptr;
216 }
217
218 if (protocol_version > kMaxSupportedProtocolVersion) {
219 LOG(FATAL) << "Unsupported protocol version " << protocol_version
220 << "; max supported version is " << kMaxSupportedProtocolVersion;
221 return nullptr;
222 }
223
224 // Send requested region.
225 int16_t size = strlen(region_name);
226 bytes = region_server->Send(&size, sizeof(size), MSG_NOSIGNAL);
227 if (bytes != sizeof(size)) {
228 LOG(FATAL) << "Failed to send region name length; res=" << bytes << " ("
229 << region_server->StrError() << ")";
230 return nullptr;
231 }
232
233 bytes = region_server->Send(region_name, size, MSG_NOSIGNAL);
234 if (bytes != size) {
235 LOG(FATAL) << "Failed to send region name; res=" << bytes << " ("
236 << region_server->StrError() << ")";
237 return nullptr;
238 }
239
240 // Receive control sockets.
241 uint64_t control_data;
242 struct iovec iov {
243 &control_data, sizeof(control_data)
244 };
245 avd::InbandMessageHeader hdr{};
246 hdr.msg_iov = &iov;
247 hdr.msg_iovlen = 1;
248 SharedFD fds[3];
249 bytes = region_server->RecvMsgAndFDs(hdr, 0, &fds);
250 if (bytes != sizeof(control_data)) {
251 LOG(FATAL) << "Failed to complete handshake; res=" << bytes << " ("
252 << region_server->StrError() << ")";
253 return nullptr;
254 }
255 HostRegionControl* rval =
256 new HostRegionControl(region_name, fds[0], fds[1], fds[2]);
257 if (!rval) {
258 return nullptr;
259 }
260 // Search for the region header
261 if (!rval->InitializeRegion()) {
262 // We already logged, so we can just bail out.
263 return nullptr;
264 }
265 return std::shared_ptr<RegionControl>(rval);
266}