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: 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 57 std::string device_path_from_name(const char* region_name) { 58 return std::string("/dev/") + region_name; 59 } 60 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 69 void GuestRegionControl::InterruptSelf() { 70 region_fd_->Ioctl(VSOC_SELF_INTERRUPT, 0); 71 } 72 73 void GuestRegionControl::WaitForInterrupt() { 74 region_fd_->Ioctl(VSOC_WAIT_FOR_INCOMING_INTERRUPT, 0); 75 } 76 77 int GuestRegionControl::SignalSelf(uint32_t offset) { 78 return region_fd_->Ioctl(VSOC_COND_WAKE, reinterpret_cast<void*>(offset)); 79 } 80 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 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 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. 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