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