blob: 1fcbd138de281a6f6c11009cf40c7883b00fd912 [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001/*
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
32using cvd::SharedFD;
33
34namespace {
35class 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
57std::string device_path_from_name(const char* region_name) {
58 return std::string("/dev/") + region_name;
59}
60
61bool 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
69void GuestRegionControl::InterruptSelf() {
70 region_fd_->Ioctl(VSOC_SELF_INTERRUPT, 0);
71}
72
73void GuestRegionControl::WaitForInterrupt() {
74 region_fd_->Ioctl(VSOC_WAIT_FOR_INCOMING_INTERRUPT, 0);
75}
76
77int GuestRegionControl::SignalSelf(uint32_t offset) {
78 return region_fd_->Ioctl(VSOC_COND_WAKE, reinterpret_cast<void*>(offset));
79}
80
81int 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
103int 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
139void* 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.
152std::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}