• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #pragma once
2 /*
3  * Copyright (C) 2016 The Android Open Source Project
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <atomic>
19 #include <cstdint>
20 #include "common/vsoc/shm/base.h"
21 
22 // Memory layout for a region that supports end-to-end (E2E) testing of
23 // shared memory regions. This verifies that all sorts of things work along the
24 // the path:
25 //
26 //   host libraries <-> ivshmem server <-> kernel <-> guest libraries
27 //
28 // This is intentionally not a unit test. The primary source of errors along
29 // this path is a misunderstanding and/or inconsistency in one of the
30 // interfaces. Introducing mocks would allow these errors to go undetected.
31 // Another way of looking at it is that the mocks would end up being a
32 // a copy-and-paste job, making a series of change-detector tests.
33 //
34 // These tests are actually run on every device boot to verify that things are
35 // ok.
36 
37 namespace vsoc {
38 namespace layout {
39 
40 namespace e2e_test {
41 
42 /**
43  * Flags that are used to indicate test status. Some of the latter testing
44  * stages rely on initializion that must be done on the peer.
45  */
46 enum E2ETestStage : uint32_t {
47   // No tests have passed
48   E2E_STAGE_NONE = 0,
49   // This side has finished writing its pattern to the region
50   E2E_MEMORY_FILLED = 1,
51   // This side has confirmed that it can see its peer's writes to the region
52   E2E_PEER_MEMORY_READ = 2,
53 };
54 static_assert(ShmTypeValidator<E2ETestStage, 4>::valid,
55               "Compilation error. Please fix above errors and retry.");
56 
57 /**
58  * Structure that grants permission to write in the region to either the guest
59  * or the host. This size of these fields is arbitrary.
60  */
61 struct E2EMemoryFill {
62   static constexpr size_t layout_size = 64;
63 
64   static const std::size_t kOwnedFieldSize = 32;
65 
66   // The compiler must not attempt to optimize away reads and writes to the
67   // shared memory window. This is pretty typical when dealing with devices
68   // doing memory mapped I/O.
69   char host_writable[kOwnedFieldSize];
70   char guest_writable[kOwnedFieldSize];
71 };
72 ASSERT_SHM_COMPATIBLE(E2EMemoryFill);
73 
74 /**
75  * Structure that grants permission to write in the region to either the guest
76  * or the host. This size of these fields is arbitrary.
77  */
78 class E2ETestStageRegister {
79  public:
80   static constexpr size_t layout_size = 4;
81 
value()82   E2ETestStage value() const {
83     return value_;
84   }
85 
set_value(E2ETestStage new_value)86   void set_value(E2ETestStage new_value) { value_ = new_value; }
87 
88  protected:
89   // The compiler must not attempt to optimize away reads and writes to the
90   // shared memory window. This is pretty typical when dealing with devices
91   // doing memory mapped I/O.
92   E2ETestStage value_;
93 };
94 ASSERT_SHM_COMPATIBLE(E2ETestStageRegister);
95 
96 /**
97  * Describes the layout of the regions used for the end-to-end test. There
98  * are multiple regions: primary and secondary, so some details like the region
99  * name must wait until later.
100  */
101 class E2ETestRegionLayout : public ::vsoc::layout::RegionLayout {
102  public:
103   static constexpr size_t layout_size = 2 * E2ETestStageRegister::layout_size +
104                                         3 * 4 + E2EMemoryFill::layout_size;
105 
106   /**
107    * Computes how many E2EMemoryFill records we need to cover the region.
108    * Covering the entire region during the test ensures that everything is
109    * mapped and coherent between guest and host.
110    */
NumFillRecords(std::size_t region_size)111   static std::size_t NumFillRecords(std::size_t region_size) {
112     if (region_size < sizeof(E2ETestRegionLayout)) {
113       return 0;
114     }
115     // 1 + ... An array of size 1 is allocated in the E2ETestRegion.
116     // TODO(ghartman): AddressSanitizer may find this sort of thing to be
117     // alarming.
118     return 1 +
119            (region_size - sizeof(E2ETestRegionLayout)) / sizeof(E2EMemoryFill);
120   }
121   // The number of test stages that have completed on the guest
122   // Later host tests will wait on this
123   E2ETestStageRegister guest_status;
124   // The number of test stages that have completed on the host
125   // Later guest tests will wait on this
126   E2ETestStageRegister host_status;
127   // These fields are used to test the signaling mechanism.
128   std::atomic<uint32_t> host_to_guest_signal;
129   std::atomic<uint32_t> guest_to_host_signal;
130   std::atomic<uint32_t> guest_self_register;
131   // There rest of the region will be filled by guest_host_strings.
132   // We actually use more than one of these, but we can't know how many
133   // until we examine the region.
134   E2EMemoryFill data[1];
135 };
136 ASSERT_SHM_COMPATIBLE(E2ETestRegionLayout);
137 
138 struct E2EPrimaryTestRegionLayout : public E2ETestRegionLayout {
139   static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
140 
141   static const char* region_name;
142   static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
143   static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
144 };
145 ASSERT_SHM_COMPATIBLE(E2EPrimaryTestRegionLayout);
146 
147 struct E2ESecondaryTestRegionLayout : public E2ETestRegionLayout {
148   static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
149 
150   static const char* region_name;
151   static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
152   static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
153 };
154 ASSERT_SHM_COMPATIBLE(E2ESecondaryTestRegionLayout);
155 
156 /**
157  * Defines an end-to-end region with a name that should never be configured.
158  */
159 struct E2EUnfindableRegionLayout : public E2ETestRegionLayout {
160   static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
161 
162   static const char* region_name;
163 };
164 ASSERT_SHM_COMPATIBLE(E2EUnfindableRegionLayout);
165 
166 }  // namespace e2e_test
167 }  // namespace layout
168 }  // namespace vsoc
169