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 "common/vsoc/lib/region_view.h"
17
18 #include <errno.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <sys/ioctl.h>
22 #include <sys/stat.h>
23 #include <sys/types.h>
24 #include <unistd.h>
25
26 #include <string>
27 #include <thread>
28
29 #include <android-base/logging.h>
30 #include <uapi/vsoc_shm.h>
31
32 using cvd::SharedFD;
33
34 namespace {
35 class GuestRegionControl : public vsoc::RegionControl {
36 public:
GuestRegionControl(const SharedFD & region_fd,const vsoc_device_region & desc)37 explicit GuestRegionControl(const SharedFD& region_fd,
38 const vsoc_device_region& desc)
39 : region_fd_{region_fd} {
40 region_desc_ = desc;
41 }
42 virtual bool InterruptPeer() override;
43 virtual void InterruptSelf() override;
44 virtual void WaitForInterrupt() override;
45 virtual void* Map() override;
46 virtual int SignalSelf(uint32_t offset) override;
47 virtual int WaitForSignal(uint32_t offset, uint32_t expected_value) override;
48
49 protected:
50 int CreateFdScopedPermission(const char* managed_region_name,
51 uint32_t owner_offset, uint32_t owned_val,
52 uint32_t begin_offset,
53 uint32_t end_offset) override;
54 cvd::SharedFD region_fd_;
55 };
56
device_path_from_name(const char * region_name)57 std::string device_path_from_name(const char* region_name) {
58 return std::string("/dev/") + region_name;
59 }
60
InterruptPeer()61 bool GuestRegionControl::InterruptPeer() {
62 int rval = region_fd_->Ioctl(VSOC_SEND_INTERRUPT_TO_HOST, 0);
63 if ((rval == -1) && (errno != EBUSY)) {
64 LOG(INFO) << __FUNCTION__ << ": ioctl failed (" << strerror(errno) << ")";
65 }
66 return !rval;
67 }
68
InterruptSelf()69 void GuestRegionControl::InterruptSelf() {
70 region_fd_->Ioctl(VSOC_SELF_INTERRUPT, 0);
71 }
72
WaitForInterrupt()73 void GuestRegionControl::WaitForInterrupt() {
74 region_fd_->Ioctl(VSOC_WAIT_FOR_INCOMING_INTERRUPT, 0);
75 }
76
SignalSelf(uint32_t offset)77 int GuestRegionControl::SignalSelf(uint32_t offset) {
78 return region_fd_->Ioctl(VSOC_COND_WAKE, reinterpret_cast<void*>(offset));
79 }
80
WaitForSignal(uint32_t offset,uint32_t expected_value)81 int GuestRegionControl::WaitForSignal(uint32_t offset,
82 uint32_t expected_value) {
83 struct vsoc_cond_wait wait;
84 wait.offset = offset;
85 wait.value = expected_value;
86 wait.wake_time_sec = 0;
87 wait.wake_time_nsec = 0;
88 wait.wait_type = VSOC_WAIT_IF_EQUAL;
89 wait.wakes = 1000;
90 wait.reserved_1 = 0;
91 int rval = region_fd_->Ioctl(VSOC_COND_WAIT, &wait);
92 if (rval == -1) {
93 return rval;
94 }
95 // Clamp the number of wakes if it overflows an integer.
96 rval = wait.wakes;
97 if (rval >= 0) {
98 return rval;
99 }
100 return INT_MAX;
101 }
102
CreateFdScopedPermission(const char * managed_region_name,uint32_t owner_offset,uint32_t owned_value,uint32_t begin_offset,uint32_t end_offset)103 int GuestRegionControl::CreateFdScopedPermission(
104 const char* managed_region_name, uint32_t owner_offset,
105 uint32_t owned_value, uint32_t begin_offset,
106 uint32_t end_offset) {
107 if (!region_fd_->IsOpen()) {
108 LOG(FATAL) << "Can't create permission before opening controller region";
109 return -EINVAL;
110 }
111 int managed_region_fd =
112 open(device_path_from_name(managed_region_name).c_str(), O_RDWR);
113 if (managed_region_fd < 0) {
114 int errno_ = errno;
115 LOG(FATAL) << "Can't open managed region: " << managed_region_name;
116 return -errno_;
117 }
118
119 fd_scoped_permission_arg perm;
120 perm.perm.begin_offset = begin_offset;
121 perm.perm.end_offset = end_offset;
122 perm.perm.owned_value = owned_value;
123 perm.perm.owner_offset = owner_offset;
124 perm.managed_region_fd = managed_region_fd;
125 LOG(INFO) << "owner offset: " << perm.perm.owner_offset;
126 int retval = region_fd_->Ioctl(VSOC_CREATE_FD_SCOPED_PERMISSION, &perm);
127 if (retval) {
128 int errno_ = errno;
129 close(managed_region_fd);
130 if (errno_ != EBUSY) {
131 LOG(FATAL) << "Unable to create fd scoped permission ("
132 << strerror(errno_) << ")";
133 }
134 return -errno_;
135 }
136 return managed_region_fd;
137 }
138
Map()139 void* GuestRegionControl::Map() {
140 region_base_ =
141 region_fd_->Mmap(0, region_size(), PROT_READ | PROT_WRITE, MAP_SHARED, 0);
142 if (region_base_ == MAP_FAILED) {
143 LOG(FATAL) << "mmap failed (" << region_fd_->StrError() << ")";
144 region_base_ = nullptr;
145 }
146 return region_base_;
147 }
148 } // namespace
149
150 // domain is here to ensure that this method has the same signature as the
151 // method on host regions.
Open(const char * region_name)152 std::shared_ptr<vsoc::RegionControl> vsoc::RegionControl::Open(
153 const char* region_name) {
154 std::string path = device_path_from_name(region_name);
155 SharedFD fd = SharedFD::Open(path.c_str(), O_RDWR);
156 if (!fd->IsOpen()) {
157 LOG(FATAL) << "Unable to open region " << region_name << " ("
158 << fd->StrError() << ")";
159 return nullptr;
160 }
161 vsoc_device_region desc;
162 if (fd->Ioctl(VSOC_DESCRIBE_REGION, &desc)) {
163 LOG(FATAL) << "Unable to obtain region descriptor (" << fd->StrError()
164 << ")";
165 return nullptr;
166 }
167 return std::shared_ptr<vsoc::RegionControl>(new GuestRegionControl(fd, desc));
168 }
169