• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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