blob: f3ae6156252648c7085439c51529852b73e8f924 [file] [log] [blame]
Cody Schuffelen134ff032019-11-22 00:25:32 -08001#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
37namespace vsoc {
38namespace layout {
39
40namespace 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 */
46enum 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};
54static_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 */
61struct 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};
72ASSERT_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 */
78class E2ETestStageRegister {
79 public:
80 static constexpr size_t layout_size = 4;
81
82 E2ETestStage value() const {
83 return value_;
84 }
85
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};
94ASSERT_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 */
101class 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 */
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};
136ASSERT_SHM_COMPATIBLE(E2ETestRegionLayout);
137
138struct 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};
145ASSERT_SHM_COMPATIBLE(E2EPrimaryTestRegionLayout);
146
147struct 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};
154ASSERT_SHM_COMPATIBLE(E2ESecondaryTestRegionLayout);
155
156/**
157 * Defines an end-to-end region with a name that should never be configured.
158 */
159struct E2EUnfindableRegionLayout : public E2ETestRegionLayout {
160 static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
161
162 static const char* region_name;
163};
164ASSERT_SHM_COMPATIBLE(E2EUnfindableRegionLayout);
165
166} // namespace e2e_test
167} // namespace layout
168} // namespace vsoc