Snap for 4796401 from 9947cc79447f3ee36ddb8c64f429eb96f11c6304 to pi-release
Change-Id: I24a328dc5b6228cf3a8bce638d9acff79480e005
diff --git a/common/vsoc/lib/vsoc_memory.cpp b/common/vsoc/lib/vsoc_memory.cpp
index f05b0b8..04f90bd 100644
--- a/common/vsoc/lib/vsoc_memory.cpp
+++ b/common/vsoc/lib/vsoc_memory.cpp
@@ -16,84 +16,361 @@
#include "common/vsoc/lib/vsoc_memory.h"
+#include <string.h>
+#include <unistd.h>
+
+#include <map>
#include <string>
#include <type_traits>
+#include "common/libs/glog/logging.h"
#include "common/vsoc/shm/audio_data_layout.h"
+#include "common/vsoc/shm/base.h"
#include "common/vsoc/shm/e2e_test_region_layout.h"
#include "common/vsoc/shm/gralloc_layout.h"
#include "common/vsoc/shm/input_events_layout.h"
#include "common/vsoc/shm/ril_layout.h"
#include "common/vsoc/shm/screen_layout.h"
#include "common/vsoc/shm/socket_forward_layout.h"
-#include "common/vsoc/shm/version.h"
#include "common/vsoc/shm/wifi_exchange_layout.h"
+#include "uapi/vsoc_shm.h"
+
+namespace {
+
+uint32_t AlignToPageSize(uint32_t val) {
+ static uint32_t page_size = sysconf(_SC_PAGESIZE);
+ return ((val + (page_size - 1)) / page_size) * page_size;
+}
+
+uint32_t AlignToPowerOf2(uint32_t val) {
+ uint32_t power_of_2 = 1;
+ while (power_of_2 < val) {
+ power_of_2 *= 2;
+ }
+ return power_of_2;
+}
+
+// Takes a vector of objects and returns a vector of pointers to those objects.
+template <typename T, typename R>
+std::vector<R*> GetConstPointers(const std::vector<T>& v) {
+ std::vector<R*> result;
+ result.reserve(v.size());
+ for (auto& element : v) {
+ result.push_back(&element);
+ }
+ return result;
+}
+} // namespace
+
namespace vsoc {
-// ShmTypeValidator provides meaningful information about the type size
-// mismatch in compilation error messages, eg.
-//
-// error:
-// static_assert failed "Class size changed, update version.h"
-// static_assert(Current == Expected,
-// note: in instantiation of template class
-// 'ShmTypeValidator<vsoc::layout::myclass::ClassName, 1232, 1240>'
-// requested here ASSERT_SHM_COMPATIBLE(ClassName, myclass);
-//
-template <typename Type, size_t Current, size_t Expected>
-struct ShmTypeValidator {
- static_assert(Current == Expected, "Class size changed, update version.h");
- static_assert(std::is_trivial<Type>(), "Class uses features that are unsafe");
- static constexpr bool valid =
- (Current == Expected) && std::is_trivial<Type>();
+namespace {
+
+class VSoCRegionLayoutImpl : public VSoCRegionLayout {
+ public:
+ VSoCRegionLayoutImpl(const char* region_name, size_t layout_size,
+ int guest_to_host_signal_table_log_size,
+ int host_to_guest_signal_table_log_size,
+ const char* managed_by)
+ : region_name_(region_name),
+ layout_size_(layout_size),
+ guest_to_host_signal_table_log_size_(
+ guest_to_host_signal_table_log_size),
+ host_to_guest_signal_table_log_size_(
+ host_to_guest_signal_table_log_size),
+ managed_by_(managed_by) {
+ size_ = GetMinRegionSize();
+ LOG(INFO) << region_name << ": is " << size_;
+ }
+ VSoCRegionLayoutImpl(const VSoCRegionLayoutImpl&) = default;
+
+ const char* region_name() const override { return region_name_; }
+ const char* managed_by() const override { return managed_by_; }
+
+ size_t layout_size() const override { return layout_size_; }
+ int guest_to_host_signal_table_log_size() const override {
+ return guest_to_host_signal_table_log_size_;
+ }
+ int host_to_guest_signal_table_log_size() const override {
+ return host_to_guest_signal_table_log_size_;
+ }
+ uint32_t begin_offset() const override { return begin_offset_; }
+ size_t region_size() const override { return size_; }
+ void SetRegionSize(size_t size) { size_ = size; }
+ void SetBeginOffset(uint32_t offset) { begin_offset_ = offset; }
+
+ // Returns the minimum size the region needs to accomodate the signaling
+ // section and the data layout.
+ size_t GetMinRegionSize() const {
+ auto size = GetOffsetOfRegionData();
+ // Data section
+ size += layout_size_;
+ size = AlignToPageSize(size);
+ return size;
+ }
+
+ uint32_t GetOffsetOfRegionData() const {
+ uint32_t offset = 0;
+ // Signal tables
+ offset += (1 << guest_to_host_signal_table_log_size_) * sizeof(uint32_t);
+ offset += (1 << host_to_guest_signal_table_log_size_) * sizeof(uint32_t);
+ // Interrup signals
+ offset += 2 * sizeof(uint32_t);
+ return offset;
+ }
+
+ private:
+ const char* region_name_{};
+ const size_t layout_size_{};
+ const int guest_to_host_signal_table_log_size_{};
+ const int host_to_guest_signal_table_log_size_{};
+ const char* managed_by_{};
+ uint32_t begin_offset_{};
+ size_t size_{};
};
-namespace {
+class VSoCMemoryLayoutImpl : public VSoCMemoryLayout {
+ public:
+ explicit VSoCMemoryLayoutImpl(std::vector<VSoCRegionLayoutImpl>&& regions)
+ : regions_(regions), region_idx_by_name_(GetNameToIndexMap(regions)) {
+ for (size_t i = 0; i < regions_.size(); ++i) {
+ // This link could be resolved later, but doing it here disables
+ // managed_by cycles among the regions.
+ if (regions[i].managed_by() &&
+ !region_idx_by_name_.count(regions[i].managed_by())) {
+ LOG(FATAL) << regions[i].region_name()
+ << " managed by unknown region: " << regions[i].managed_by()
+ << ". Manager Regions must be declared before the regions "
+ "they manage";
+ }
+ }
+
+ uint32_t offset = 0;
+ // Reserve space for global header
+ offset += sizeof(vsoc_shm_layout_descriptor);
+ // and region descriptors
+ offset += regions_.size() * sizeof(vsoc_device_region);
+ offset = AlignToPageSize(offset);
+
+ // Calculate offsets for all regions and set the size of the device
+ UpdateRegionOffsetsAndDeviceSize(offset);
+ }
+
+ ~VSoCMemoryLayoutImpl() = default;
+
+ std::vector<const VSoCRegionLayout*> GetRegions() const {
+ static std::vector<const VSoCRegionLayout*> ret =
+ GetConstPointers<VSoCRegionLayoutImpl, const VSoCRegionLayout>(
+ regions_);
+ return ret;
+ }
+
+ const VSoCRegionLayout* GetRegionByName(
+ const char* region_name) const override {
+ if (!region_idx_by_name_.count(region_name)) {
+ return nullptr;
+ }
+ return ®ions_[region_idx_by_name_.at(region_name)];
+ }
+
+ uint32_t GetMemoryFileSize() const override { return device_size_; }
+
+ void WriteLayout(void* shared_memory) const override;
+
+ bool ResizeRegion(const char* region_name, size_t new_min_size) override {
+ if (!region_idx_by_name_.count(region_name)) {
+ LOG(ERROR) << "Unable to resize region: " << region_name
+ << ". Region not found";
+ return false;
+ }
+ auto index = region_idx_by_name_.at(region_name);
+ auto& region = regions_[index];
+ auto min_required_size = region.GetMinRegionSize();
+
+ // Align to page size
+ new_min_size = AlignToPageSize(new_min_size);
+ if (new_min_size < min_required_size) {
+ LOG(ERROR) << "Requested resize of region " << region_name << " to "
+ << new_min_size << " (after alignment), it needs at least "
+ << min_required_size << " bytes.";
+ return false;
+ }
+
+ region.SetRegionSize(new_min_size);
+
+ // Get new offset for next region
+ auto offset = region.begin_offset() + region.region_size();
+ // Update offsets for all following regions
+ UpdateRegionOffsetsAndDeviceSize(offset, index + 1);
+ return true;
+ }
+
+ protected:
+ VSoCMemoryLayoutImpl() = delete;
+ VSoCMemoryLayoutImpl(const VSoCMemoryLayoutImpl&) = delete;
+
+ // Helper function to allow the creation of the name to index map in the
+ // constructor and allow the field to be const
+ static std::map<const char*, size_t> GetNameToIndexMap(
+ const std::vector<VSoCRegionLayoutImpl>& regions) {
+ std::map<const char*, size_t> result;
+ for (size_t index = 0; index < regions.size(); ++index) {
+ auto region_name = regions[index].region_name();
+ if (result.count(region_name)) {
+ LOG(FATAL) << region_name << " used for more than one region";
+ }
+ result[region_name] = index;
+ }
+ return result;
+ }
+
+ // Updates the beginning offset of all regions starting at a specific index
+ // (useful after a resize operation) and the device's size.
+ void UpdateRegionOffsetsAndDeviceSize(uint32_t offset, size_t index = 0) {
+ for (; index < regions_.size(); ++index) {
+ regions_[index].SetBeginOffset(offset);
+ offset += regions_[index].region_size();
+ }
+
+ // Make the device's size the smaller power of two possible
+ device_size_ = AlignToPowerOf2(offset);
+ }
+
+ std::vector<VSoCRegionLayoutImpl> regions_;
+ const std::map<const char*, size_t> region_idx_by_name_;
+ uint32_t device_size_{};
+};
+
+// Writes a region's signal table layout to shared memory. Returns the region
+// offset of free memory after the table and interrupt signaled word.
+uint32_t WriteSignalTableDescription(vsoc_signal_table_layout* layout,
+ uint32_t offset, int log_size) {
+ layout->num_nodes_lg2 = log_size;
+ // First the signal table
+ layout->futex_uaddr_table_offset = offset;
+ offset += (1 << log_size) * sizeof(uint32_t);
+ // Then the interrupt signaled word
+ layout->interrupt_signalled_offset = offset;
+ offset += sizeof(uint32_t);
+ return offset;
+}
+
+// Writes a region's layout description to shared memory
+void WriteRegionDescription(vsoc_device_region* shmem_region_desc,
+ const VSoCRegionLayoutImpl& region) {
+ // Region versions are deprecated, write some sensible value
+ shmem_region_desc->current_version = 0;
+ shmem_region_desc->min_compatible_version = 0;
+
+ shmem_region_desc->region_begin_offset = region.begin_offset();
+ shmem_region_desc->region_end_offset =
+ region.begin_offset() + region.region_size();
+ shmem_region_desc->offset_of_region_data = region.GetOffsetOfRegionData();
+ strncpy(shmem_region_desc->device_name, region.region_name(),
+ VSOC_DEVICE_NAME_SZ - 1);
+ shmem_region_desc->device_name[VSOC_DEVICE_NAME_SZ - 1] = '\0';
+ // Guest to host signal table at the beginning of the region
+ uint32_t offset = 0;
+ offset = WriteSignalTableDescription(
+ &shmem_region_desc->guest_to_host_signal_table, offset,
+ region.guest_to_host_signal_table_log_size());
+ // Host to guest signal table right after
+ offset = WriteSignalTableDescription(
+ &shmem_region_desc->host_to_guest_signal_table, offset,
+ region.host_to_guest_signal_table_log_size());
+ // Double check that the region metadata does not collide with the data
+ if (offset > shmem_region_desc->offset_of_region_data) {
+ LOG(FATAL) << "Error: Offset of region data too small (is "
+ << shmem_region_desc->offset_of_region_data << " should be "
+ << offset << " ) for region " << region.region_name()
+ << ". This is a bug";
+ }
+}
+
+void VSoCMemoryLayoutImpl::WriteLayout(void* shared_memory) const {
+ // Device header
+ static_assert(CURRENT_VSOC_LAYOUT_MAJOR_VERSION == 2,
+ "Region layout code must be updated");
+ auto header = reinterpret_cast<vsoc_shm_layout_descriptor*>(shared_memory);
+ header->major_version = CURRENT_VSOC_LAYOUT_MAJOR_VERSION;
+ header->minor_version = CURRENT_VSOC_LAYOUT_MINOR_VERSION;
+ header->size = GetMemoryFileSize();
+ header->region_count = regions_.size();
+
+ // Region descriptions go right after the layout descriptor
+ header->vsoc_region_desc_offset = sizeof(vsoc_shm_layout_descriptor);
+ auto region_descriptions = reinterpret_cast<vsoc_device_region*>(header + 1);
+ for (size_t idx = 0; idx < regions_.size(); ++idx) {
+ auto shmem_region_desc = ®ion_descriptions[idx];
+ const auto& region = regions_[idx];
+ WriteRegionDescription(shmem_region_desc, region);
+ // Handle managed_by links
+ if (region.managed_by()) {
+ auto manager_idx = region_idx_by_name_.at(region.managed_by());
+ if (manager_idx == VSOC_REGION_WHOLE) {
+ LOG(FATAL) << "Region '" << region.region_name() << "' has owner "
+ << region.managed_by() << " with index " << manager_idx
+ << " which is the default value for regions without an "
+ "owner. Choose a different region to be at index "
+ << manager_idx
+ << ", make sure the chosen region is NOT the owner of any "
+ "other region";
+ }
+ shmem_region_desc->managed_by = manager_idx;
+ } else {
+ shmem_region_desc->managed_by = VSOC_REGION_WHOLE;
+ }
+ }
+}
+
template <class R>
-RegionMemoryLayout ValidateAndBuildLayout(int region_size,
- int g_to_h_signal_table_log_size,
- int h_to_g_signal_table_log_size,
- const char* managed_by = nullptr) {
- static_assert(
- ShmTypeValidator<R, sizeof(R), vsoc::layout::VersionInfo<R>::size>::valid,
- "Compilation error. Please fix above errors and retry.");
- return RegionMemoryLayout(R::region_name, region_size,
- g_to_h_signal_table_log_size,
- h_to_g_signal_table_log_size, managed_by);
+VSoCRegionLayoutImpl ValidateAndBuildLayout(int g_to_h_signal_table_log_size,
+ int h_to_g_signal_table_log_size,
+ const char* managed_by = nullptr) {
+ // Double check that the Layout is a valid shm type.
+ ASSERT_SHM_COMPATIBLE(R);
+ return VSoCRegionLayoutImpl(R::region_name, sizeof(R),
+ g_to_h_signal_table_log_size,
+ h_to_g_signal_table_log_size, managed_by);
}
} // namespace
-const std::vector<RegionMemoryLayout>& GetVsocMemoryLayout() {
- static const std::vector<RegionMemoryLayout> layout = {
- ValidateAndBuildLayout<layout::input_events::InputEventsLayout>(
- /*size*/ 4096, /*g->h*/ 2, /*h->g*/ 2),
- ValidateAndBuildLayout<layout::screen::ScreenLayout>(
- /*size*/ 12292096, /*g->h*/ 2, /*h->g*/ 2),
- ValidateAndBuildLayout<layout::gralloc::GrallocManagerLayout>(
- /*size*/ 40960, /*g->h*/ 2, /*h->g*/ 2),
- ValidateAndBuildLayout<layout::gralloc::GrallocBufferLayout>(
- /*size*/ 407142400, /*g->h*/ 0, /*h->g*/ 0,
- /* managed_by */ layout::gralloc::GrallocManagerLayout::region_name),
- ValidateAndBuildLayout<layout::socket_forward::SocketForwardLayout>(
- /*size*/ 2105344, /*g->h*/ 7, /*h->g*/ 7),
- ValidateAndBuildLayout<layout::wifi::WifiExchangeLayout>(
- /*size*/ 139264, /*g->h*/ 2, /*h->g*/ 2),
- ValidateAndBuildLayout<layout::ril::RilLayout>(
- /*size*/ 4096, /*g->h*/ 2, /*h->g*/ 2),
- ValidateAndBuildLayout<layout::e2e_test::E2EPrimaryTestRegionLayout>(
- /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
- ValidateAndBuildLayout<layout::e2e_test::E2ESecondaryTestRegionLayout>(
- /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
- ValidateAndBuildLayout<layout::e2e_test::E2EManagerTestRegionLayout>(
- /*size*/ 4096, /*g->h*/ 1, /*h->g*/ 1),
- ValidateAndBuildLayout<layout::e2e_test::E2EManagedTestRegionLayout>(
- /*size*/ 16384, /*g->h*/ 1, /*h->g*/ 1),
- ValidateAndBuildLayout<layout::audio_data::AudioDataLayout>(
- /*size*/ 20480, /*g->h*/ 2, /*h->g*/ 2)};
+VSoCMemoryLayout* VSoCMemoryLayout::Get() {
+ /*******************************************************************
+ * Make sure the first region is not the manager of other regions. *
+ * This error will only be caught on runtime!!!!! *
+ *******************************************************************/
+ static VSoCMemoryLayoutImpl layout(
+ {ValidateAndBuildLayout<layout::input_events::InputEventsLayout>(2, 2),
+ ValidateAndBuildLayout<layout::screen::ScreenLayout>(2, 2),
+ ValidateAndBuildLayout<layout::gralloc::GrallocManagerLayout>(2, 2),
+ ValidateAndBuildLayout<layout::gralloc::GrallocBufferLayout>(
+ 0, 0,
+ /* managed_by */ layout::gralloc::GrallocManagerLayout::region_name),
+ ValidateAndBuildLayout<layout::socket_forward::SocketForwardLayout>(7,
+ 7),
+ ValidateAndBuildLayout<layout::wifi::WifiExchangeLayout>(2, 2),
+ ValidateAndBuildLayout<layout::ril::RilLayout>(2, 2),
+ ValidateAndBuildLayout<layout::e2e_test::E2EPrimaryTestRegionLayout>(1,
+ 1),
+ ValidateAndBuildLayout<layout::e2e_test::E2ESecondaryTestRegionLayout>(
+ 1, 1),
+ ValidateAndBuildLayout<layout::e2e_test::E2EManagerTestRegionLayout>(1,
+ 1),
+ ValidateAndBuildLayout<layout::e2e_test::E2EManagedTestRegionLayout>(1,
+ 1),
+ ValidateAndBuildLayout<layout::audio_data::AudioDataLayout>(2, 2)});
- return layout;
+ // We need this code to compile on both sides to enforce the static checks,
+ // but should only be used host side if for no other reason because of the
+ // possible resizing of some regions not being visible on the guest.
+#if !defined(CUTTLEFISH_HOST)
+ LOG(FATAL) << "Memory layout is not accurate in guest side, use region "
+ "classes or the vsoc driver directly instead.";
+#endif
+ return &layout;
}
} // namespace vsoc
diff --git a/common/vsoc/lib/vsoc_memory.h b/common/vsoc/lib/vsoc_memory.h
index b6844b8..011e693 100644
--- a/common/vsoc/lib/vsoc_memory.h
+++ b/common/vsoc/lib/vsoc_memory.h
@@ -15,44 +15,55 @@
* limitations under the License.
*/
+#include <stdint.h>
+
#include <vector>
namespace vsoc {
-class RegionMemoryLayout {
+class VSoCRegionLayout {
public:
- RegionMemoryLayout(const char* region_name, size_t region_size,
- int guest_to_host_signal_table_log_size,
- int host_to_guest_signal_table_log_size,
- const char* managed_by)
- : region_name_(region_name),
- region_size_(region_size),
- guest_to_host_signal_table_log_size_(
- guest_to_host_signal_table_log_size),
- host_to_guest_signal_table_log_size_(
- host_to_guest_signal_table_log_size),
- managed_by_(managed_by) {}
+ virtual const char* region_name() const = 0;
+ virtual const char* managed_by() const = 0;
- const char* region_name() const { return region_name_; }
- size_t region_size() const { return region_size_; }
- int guest_to_host_signal_table_log_size() const {
- return guest_to_host_signal_table_log_size_;
- }
- int host_to_guest_signal_table_log_size() const {
- return host_to_guest_signal_table_log_size_;
- }
- const char * managed_by() const {
- return managed_by_;
- }
-
- private:
- const char* region_name_{};
- size_t region_size_{};
- int guest_to_host_signal_table_log_size_{};
- int host_to_guest_signal_table_log_size_{};
- const char* managed_by_{};
+ virtual size_t layout_size() const = 0;
+ virtual int guest_to_host_signal_table_log_size() const = 0;
+ virtual int host_to_guest_signal_table_log_size() const = 0;
+ virtual uint32_t begin_offset() const = 0;
+ virtual size_t region_size() const = 0;
+ protected:
+ VSoCRegionLayout() = default;
+ virtual ~VSoCRegionLayout() = default;
};
-const std::vector<RegionMemoryLayout>& GetVsocMemoryLayout();
+class VSoCMemoryLayout {
+ public:
+ // Returns a pointer to the memory layout singleton.
+ static VSoCMemoryLayout* Get();
+
+ VSoCMemoryLayout(const VSoCMemoryLayout&) = delete;
+ VSoCMemoryLayout(VSoCMemoryLayout&&) = delete;
+
+ virtual std::vector<const VSoCRegionLayout *> GetRegions() const = 0;
+ virtual const VSoCRegionLayout* GetRegionByName(
+ const char* region_name) const = 0;
+
+ // Returns the smallest number of bytes that is a power of 2 and can
+ // accomodate the entire memory layout.
+ virtual uint32_t GetMemoryFileSize() const = 0;
+
+ // Writes the layout to memory. shared_memory should be the result of mmap-ing
+ // a file of at least GetMemoryFileSize() bytes.
+ virtual void WriteLayout(void * shared_memory) const = 0;
+
+ // Increase the size of the data section of a region to make the entire region
+ // at least new_min_size bytes. The actual region size will be no less than
+ // the minimum size required to accomodate the signal tables and the memory
+ // layout, and will be aligned to page size.
+ virtual bool ResizeRegion(const char* region_name, size_t new_min_size) = 0;
+ protected:
+ VSoCMemoryLayout() = default;
+ virtual ~VSoCMemoryLayout() = default;
+};
} // namespace vsoc
diff --git a/common/vsoc/shm/audio_data_layout.h b/common/vsoc/shm/audio_data_layout.h
index 30df4f8..3991ea0 100644
--- a/common/vsoc/shm/audio_data_layout.h
+++ b/common/vsoc/shm/audio_data_layout.h
@@ -26,10 +26,12 @@
struct AudioDataLayout : public RegionLayout {
static const char *const region_name;
+ static constexpr size_t layout_size = 16396;
// size = 2^14 = 16384, packets are up to 4KB bytes each.
CircularPacketQueue<14, 4096> audio_queue;
};
+ASSERT_SHM_COMPATIBLE(AudioDataLayout);
} // namespace audio_data
} // namespace layout
diff --git a/common/vsoc/shm/base.h b/common/vsoc/shm/base.h
index 7bbaeb9..f5abec8 100644
--- a/common/vsoc/shm/base.h
+++ b/common/vsoc/shm/base.h
@@ -16,8 +16,31 @@
*/
#include <stdint.h>
+#include <type_traits>
// Base macros for all layout structures.
+// ShmTypeValidator provides meaningful information about the type size
+// mismatch in compilation error messages, eg.
+//
+// error:
+// static_assert failed "Class size changed, update the layout_size field"
+// static_assert(Current == Expected,
+// note: in instantiation of template class
+// 'ShmTypeValidator<vsoc::layout::myclass::ClassName>'
+// requested here ASSERT_SHM_COMPATIBLE(ClassName);
+//
+template <typename Type, size_t expected_size = Type::layout_size>
+struct ShmTypeValidator {
+ static_assert(sizeof(Type) == expected_size,
+ "Class size changed, update the layout_size field");
+ static_assert(std::is_trivial<Type>(), "Class uses features that are unsafe");
+ static constexpr bool valid =
+ sizeof(Type) == expected_size && std::is_trivial<Type>();
+};
+
+#define ASSERT_SHM_COMPATIBLE(T) \
+ static_assert(ShmTypeValidator<T>::valid, \
+ "Compilation error. Please fix above errors and retry.")
namespace vsoc {
namespace layout {
@@ -42,12 +65,18 @@
Peer = Host
#endif
};
+// Enums can't have static members, so can't use the macro here.
+ static_assert(ShmTypeValidator<Sides, 4>::valid,
+ "Compilation error. Please fix above errors and retry.");
/**
* Base class for all region layout structures.
*/
class RegionLayout {
+public:
+ static constexpr size_t layout_size = 1;
};
+ASSERT_SHM_COMPATIBLE(RegionLayout);
} // namespace layout
} // namespace vsoc
diff --git a/common/vsoc/shm/circqueue.h b/common/vsoc/shm/circqueue.h
index aacdd2b..05893bf 100644
--- a/common/vsoc/shm/circqueue.h
+++ b/common/vsoc/shm/circqueue.h
@@ -36,6 +36,10 @@
*/
template <uint32_t SizeLog2>
class CircularQueueBase {
+ public:
+ static constexpr size_t layout_size = (1 << SizeLog2) + 12;
+
+ private:
CircularQueueBase() = delete;
CircularQueueBase(const CircularQueueBase&) = delete;
CircularQueueBase& operator=(const CircularQueueBase&) = delete;
@@ -101,6 +105,7 @@
char buffer_[BufferSize];
};
using CircularQueueBase64k = CircularQueueBase<16>;
+ASSERT_SHM_COMPATIBLE(CircularQueueBase64k);
/**
* Byte oriented circular queue. Reads will always return some data, but
@@ -110,6 +115,8 @@
template <uint32_t SizeLog2>
class CircularByteQueue : public CircularQueueBase<SizeLog2> {
public:
+ static constexpr size_t layout_size =
+ CircularQueueBase<SizeLog2>::layout_size;
/**
* Read at most max_size bytes from the qeueue, placing them in buffer_out
*/
@@ -134,6 +141,7 @@
using Range = typename CircularQueueBase<SizeLog2>::Range;
};
using CircularByteQueue64k = CircularByteQueue<16>;
+ASSERT_SHM_COMPATIBLE(CircularByteQueue64k);
/**
* Packet oriented circular queue. Reads will either return data or an error.
@@ -143,6 +151,9 @@
template <uint32_t SizeLog2, uint32_t MaxPacketSize>
class CircularPacketQueue : public CircularQueueBase<SizeLog2> {
public:
+ static constexpr size_t layout_size =
+ CircularQueueBase<SizeLog2>::layout_size;
+
/**
* Read a single packet from the queue, placing its data into buffer_out.
* If max_size indicates that buffer_out cannot hold the entire packet
@@ -186,6 +197,7 @@
intptr_t CalculateBufferedSize(size_t payload);
};
using CircularPacketQueue64k = CircularPacketQueue<16, 1024>;
+ASSERT_SHM_COMPATIBLE(CircularPacketQueue64k);
} // namespace layout
} // namespace vsoc
diff --git a/common/vsoc/shm/e2e_test_region_layout.h b/common/vsoc/shm/e2e_test_region_layout.h
index 8853211..2c2670b 100644
--- a/common/vsoc/shm/e2e_test_region_layout.h
+++ b/common/vsoc/shm/e2e_test_region_layout.h
@@ -43,7 +43,7 @@
* Flags that are used to indicate test status. Some of the latter testing
* stages rely on initializion that must be done on the peer.
*/
-enum E2ETestStage {
+ enum E2ETestStage : uint32_t {
// No tests have passed
E2E_STAGE_NONE = 0,
// This side has finished writing its pattern to the region
@@ -51,12 +51,16 @@
// This side has confirmed that it can see its peer's writes to the region
E2E_PEER_MEMORY_READ = 2,
};
+static_assert(ShmTypeValidator<E2ETestStage, 4>::valid,
+ "Compilation error. Please fix above errors and retry.");
/**
* Structure that grants permission to write in the region to either the guest
* or the host. This size of these fields is arbitrary.
*/
struct E2EMemoryFill {
+ static constexpr size_t layout_size = 64;
+
static const std::size_t kOwnedFieldSize = 32;
// The compiler must not attempt to optimize away reads and writes to the
@@ -65,6 +69,7 @@
char host_writable[kOwnedFieldSize];
char guest_writable[kOwnedFieldSize];
};
+ASSERT_SHM_COMPATIBLE(E2EMemoryFill);
/**
* Structure that grants permission to write in the region to either the guest
@@ -72,9 +77,10 @@
*/
class E2ETestStageRegister {
public:
+ static constexpr size_t layout_size = 4;
+
E2ETestStage value() const {
- E2ETestStage rval = static_cast<E2ETestStage>(value_);
- return rval;
+ return value_;
}
void set_value(E2ETestStage new_value) { value_ = new_value; }
@@ -83,8 +89,9 @@
// The compiler must not attempt to optimize away reads and writes to the
// shared memory window. This is pretty typical when dealing with devices
// doing memory mapped I/O.
- uint32_t value_;
+ E2ETestStage value_;
};
+ASSERT_SHM_COMPATIBLE(E2ETestStageRegister);
/**
* Describes the layout of the regions used for the end-to-end test. There
@@ -93,6 +100,9 @@
*/
class E2ETestRegionLayout : public ::vsoc::layout::RegionLayout {
public:
+ static constexpr size_t layout_size = 2 * E2ETestStageRegister::layout_size +
+ 3 * 4 + E2EMemoryFill::layout_size;
+
/**
* Computes how many E2EMemoryFill records we need to cover the region.
* Covering the entire region during the test ensures that everything is
@@ -123,36 +133,52 @@
// until we examine the region.
E2EMemoryFill data[1];
};
+ASSERT_SHM_COMPATIBLE(E2ETestRegionLayout);
struct E2EPrimaryTestRegionLayout : public E2ETestRegionLayout {
+ static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
static const char* region_name;
static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
};
+ASSERT_SHM_COMPATIBLE(E2EPrimaryTestRegionLayout);
struct E2ESecondaryTestRegionLayout : public E2ETestRegionLayout {
+ static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
static const char* region_name;
static const char guest_pattern[E2EMemoryFill::kOwnedFieldSize];
static const char host_pattern[E2EMemoryFill::kOwnedFieldSize];
};
+ASSERT_SHM_COMPATIBLE(E2ESecondaryTestRegionLayout);
/**
* Defines an end-to-end region with a name that should never be configured.
*/
struct E2EUnfindableRegionLayout : public E2ETestRegionLayout {
+ static constexpr size_t layout_size = E2ETestRegionLayout::layout_size;
+
static const char* region_name;
};
+ASSERT_SHM_COMPATIBLE(E2EUnfindableRegionLayout);
struct E2EManagedTestRegionLayout : public RegionLayout {
+ static constexpr size_t layout_size = 4;
+
static const char* region_name;
uint32_t val; // Not needed, here only to avoid an empty struct.
};
+ASSERT_SHM_COMPATIBLE(E2EManagedTestRegionLayout);
struct E2EManagerTestRegionLayout : public RegionLayout {
+ static constexpr size_t layout_size = 4 * 4;
+
static const char* region_name;
typedef E2EManagedTestRegionLayout ManagedRegion;
uint32_t data[4]; // We don't need more than 4 for the tests
};
+ASSERT_SHM_COMPATIBLE(E2EManagerTestRegionLayout);
} // namespace e2e_test
} // namespace layout
diff --git a/common/vsoc/shm/gralloc_layout.h b/common/vsoc/shm/gralloc_layout.h
index 3e0c883..4da740f 100644
--- a/common/vsoc/shm/gralloc_layout.h
+++ b/common/vsoc/shm/gralloc_layout.h
@@ -27,6 +27,9 @@
namespace gralloc {
struct BufferEntry {
+ static constexpr size_t layout_size =
+ 7 * 4 + PixelFormatRegister::layout_size;
+
uint32_t owned_by;
uint32_t buffer_begin;
uint32_t buffer_end;
@@ -44,12 +47,17 @@
return buffer_end - buffer_begin;
}
};
+ASSERT_SHM_COMPATIBLE(BufferEntry);
struct GrallocBufferLayout : public RegionLayout {
+ static constexpr size_t layout_size = 1;
static const char* region_name;
};
+ASSERT_SHM_COMPATIBLE(GrallocBufferLayout);
struct GrallocManagerLayout : public RegionLayout {
+ static constexpr size_t layout_size =
+ 8 + GuestLock::layout_size + BufferEntry::layout_size;
static const char* region_name;
typedef GrallocBufferLayout ManagedRegion;
@@ -60,6 +68,7 @@
// Needs to be last field
BufferEntry buffers_table[1];
};
+ASSERT_SHM_COMPATIBLE(GrallocManagerLayout);
} // namespace gralloc
} // namespace layout
diff --git a/common/vsoc/shm/graphics.h b/common/vsoc/shm/graphics.h
index f29e0cf..0aa7875 100644
--- a/common/vsoc/shm/graphics.h
+++ b/common/vsoc/shm/graphics.h
@@ -68,7 +68,7 @@
// * Observant reviewers can verify that the same pixel value is not assigned
// to multiple formats. Keep the enums in numerical order below to
// make this easier.
-enum PixelFormat {
+enum PixelFormat : uint32_t {
VSOC_PIXEL_FORMAT_UNINITIALIZED = PixelFormatBuilder<1,0>::value,
VSOC_PIXEL_FORMAT_BLOB = PixelFormatBuilder<1,1>::value,
@@ -129,25 +129,34 @@
// VSOC_PIXEL_FORMAT_sRGB_X_8888
// VSOC_PIXEL_FORMAT_sRGB_A_8888
};
+// Enums can't have static members, so can't use the macro here.
+static_assert(ShmTypeValidator<PixelFormat, 4>::valid,
+ "Compilation error. Please fix above errors and retry.");
namespace layout {
// VSoC memory layout for a register that accepts a single pixel format.
// The value is volatile to ensure that the compiler does not eliminate stores.
struct PixelFormatRegister {
+ static constexpr size_t layout_size = 4;
+
volatile PixelFormat value_;
};
+ASSERT_SHM_COMPATIBLE(PixelFormatRegister);
// Register layout for a mask giving different PixelFormats. Reserve enough
// space to allow for future expansion. For example, we may well end with
// a 12 bit per channel format in the future.
struct PixelFormatMaskRegister {
+ static constexpr size_t layout_size = 8;
+
volatile uint64_t value_;
bool HasValue(PixelFormat in) {
return !!(value_ & (uint64_t(1) << in));
}
};
+ASSERT_SHM_COMPATIBLE(PixelFormatMaskRegister);
// Ensure that the mask is large enough to hold the highest encodable
// pixel format.
diff --git a/common/vsoc/shm/input_events_layout.h b/common/vsoc/shm/input_events_layout.h
index 7cb4654..737c903 100644
--- a/common/vsoc/shm/input_events_layout.h
+++ b/common/vsoc/shm/input_events_layout.h
@@ -26,6 +26,10 @@
namespace input_events {
struct InputEventsLayout : public RegionLayout {
+ static constexpr size_t layout_size =
+ CircularPacketQueue<10, 256>::layout_size +
+ 2 * CircularPacketQueue<10, 16>::layout_size;
+
static const char* region_name;
// Event queues for the different input devices supported. Both the power
// button and the keyboard need only generate 2 input events for every
@@ -35,6 +39,7 @@
CircularPacketQueue<10, 16> keyboard_queue;
CircularPacketQueue<10, 16> power_button_queue;
};
+ASSERT_SHM_COMPATIBLE(InputEventsLayout);
} // namespace input_events
} // namespace layout
diff --git a/common/vsoc/shm/lock.h b/common/vsoc/shm/lock.h
index 6ebdaa2..cc86add 100644
--- a/common/vsoc/shm/lock.h
+++ b/common/vsoc/shm/lock.h
@@ -50,6 +50,8 @@
*/
class SpinLock {
public:
+ static constexpr size_t layout_size = 4;
+
/**
* Acquire the spinlock on the queue. This will effectively block all
* readers and writers.
@@ -87,12 +89,16 @@
protected:
std::atomic<uint32_t> lock_;
};
+ASSERT_SHM_COMPATIBLE(SpinLock);
/**
* This is a generic synchronization primitive that provides space for the
* owner of the lock to write platform-specific information.
*/
class WaitingLockBase {
+ public:
+ static constexpr size_t layout_size = 40;
+
protected:
// Common code to handle locking
// Must be called with the kernel's thread id
@@ -137,6 +143,7 @@
int64_t owner_scratch_[2];
#pragma clang diagnostic pop
};
+ASSERT_SHM_COMPATIBLE(WaitingLockBase);
/**
* GuestLocks can be acquired and released only on the guest. They reside
@@ -148,6 +155,8 @@
*/
class GuestLock : public WaitingLockBase {
public:
+ static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
#ifndef CUTTLEFISH_HOST
void Lock();
void Unlock();
@@ -161,6 +170,7 @@
bool Recover();
#endif
};
+ASSERT_SHM_COMPATIBLE(GuestLock);
/**
* HostLocks can be acquired and released only on the host. They reside
@@ -172,6 +182,8 @@
*/
class HostLock : public WaitingLockBase {
public:
+ static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
#ifdef CUTTLEFISH_HOST
void Lock();
void Unlock();
@@ -186,6 +198,7 @@
bool Recover();
#endif
};
+ASSERT_SHM_COMPATIBLE(HostLock);
/**
* GuestAndHostLocks can be acquired and released on either side of the
@@ -213,6 +226,8 @@
*/
class GuestAndHostLock : public WaitingLockBase {
public:
+ static constexpr size_t layout_size = WaitingLockBase::layout_size;
+
void Lock(RegionView*);
void Unlock(RegionView*);
/**
@@ -225,6 +240,7 @@
*/
bool Recover(RegionView*);
};
+ASSERT_SHM_COMPATIBLE(GuestAndHostLock);
} // namespace layout
} // namespace vsoc
diff --git a/common/vsoc/shm/ril_layout.h b/common/vsoc/shm/ril_layout.h
index 8910bde..33348e2 100644
--- a/common/vsoc/shm/ril_layout.h
+++ b/common/vsoc/shm/ril_layout.h
@@ -24,6 +24,7 @@
namespace ril {
struct RilLayout : public RegionLayout {
+ static constexpr size_t layout_size = 4 * 16 + 4;
static const char* region_name;
char ipaddr[16]; // xxx.xxx.xxx.xxx\0 = 16 bytes
@@ -32,6 +33,7 @@
char broadcast[16];
uint32_t prefixlen;
};
+ASSERT_SHM_COMPATIBLE(RilLayout);
} // namespace ril
} // namespace layout
} // namespace vsoc
diff --git a/common/vsoc/shm/screen_layout.h b/common/vsoc/shm/screen_layout.h
index 3e54c6c..7ad0ca3 100644
--- a/common/vsoc/shm/screen_layout.h
+++ b/common/vsoc/shm/screen_layout.h
@@ -15,8 +15,6 @@
* limitations under the License.
*/
-#include <vector>
-
#include "common/vsoc/shm/base.h"
#include "common/vsoc/shm/lock.h"
@@ -27,13 +25,19 @@
namespace screen {
struct TimeSpec {
+ static constexpr size_t layout_size = 16;
+
int64_t ts_sec;
uint32_t ts_nsec;
// Host and guest compilers are giving the structure different sizes without
// this field.
uint32_t reserved;
};
+ASSERT_SHM_COMPATIBLE(TimeSpec);
+
struct CompositionStats {
+ static constexpr size_t layout_size = 4 + 2 * 2 + 5 * TimeSpec::layout_size;
+
uint32_t num_prepare_calls;
uint16_t num_layers;
uint16_t num_hwcomposited_layers;
@@ -43,8 +47,10 @@
TimeSpec set_start;
TimeSpec set_end;
};
+ASSERT_SHM_COMPATIBLE(CompositionStats);
struct ScreenLayout : public RegionLayout {
+ static constexpr size_t layout_size = 24 + CompositionStats::layout_size;
static const char* region_name;
// Display properties
uint32_t x_res;
@@ -62,6 +68,7 @@
CompositionStats stats;
uint8_t buffer[0];
};
+ASSERT_SHM_COMPATIBLE(ScreenLayout);
} // namespace screen
diff --git a/common/vsoc/shm/socket_forward_layout.h b/common/vsoc/shm/socket_forward_layout.h
index 69d4ae2..5c78f21 100644
--- a/common/vsoc/shm/socket_forward_layout.h
+++ b/common/vsoc/shm/socket_forward_layout.h
@@ -36,8 +36,13 @@
// If both are closed then the queue goes back to INACTIVE
// BOTH_CLOSED = 0,
};
+static_assert(ShmTypeValidator<QueueState, 4>::valid,
+ "Compilation error. Please fix above errors and retry.");
struct Queue {
+ static constexpr size_t layout_size =
+ CircularPacketQueue<16, kMaxPacketSize>::layout_size + 4;
+
CircularPacketQueue<16, kMaxPacketSize> queue;
QueueState queue_state_;
@@ -46,8 +51,11 @@
return queue.Recover();
}
};
+ASSERT_SHM_COMPATIBLE(Queue);
struct QueuePair {
+ static constexpr size_t layout_size = 2 * Queue::layout_size + 8;
+
// Traffic originating from host that proceeds towards guest.
Queue host_to_guest;
// Traffic originating from guest that proceeds towards host.
@@ -67,8 +75,11 @@
return recovered;
}
};
+ASSERT_SHM_COMPATIBLE(QueuePair);
struct SocketForwardLayout : public RegionLayout {
+ static constexpr size_t layout_size = QueuePair::layout_size * kNumQueues + 8;
+
bool Recover() {
bool recovered = false;
for (auto& i : queues_) {
@@ -85,6 +96,8 @@
static const char* region_name;
};
+ASSERT_SHM_COMPATIBLE(SocketForwardLayout);
+
} // namespace socket_forward
} // namespace layout
} // namespace vsoc
diff --git a/common/vsoc/shm/version.h b/common/vsoc/shm/version.h
deleted file mode 100644
index cc2e6b6..0000000
--- a/common/vsoc/shm/version.h
+++ /dev/null
@@ -1,175 +0,0 @@
-#pragma once
-
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// Version information for structures that are present in VSoC shared memory
-// windows. The proper use of this file will:
-//
-// * ensure that the guest and host builds agree on the sizes of the shared
-// structures.
-//
-// * provides a single version code for the entire vsoc layout, assuming
-// that reviewers excercise some care.
-//
-//
-// Use:
-//
-// Every new class / structure in the shm folder needs to add a size
-// entry here, #include the base.h file, and add a ASSERT_SHM_COMPATIBLE
-// instantiation just below the class definition,
-//
-// For templatized classes / structs the author should choose a fixed size,
-// create a using alias, and instantiate the checks on the alias.
-// See CircularByteQueue64k for an example of this usage.
-//
-// Note to reviewers:
-//
-// It is probably ok to approve new additions here without forcing a
-// a version change.
-//
-// However, the version must increment for any change in the value of a
-// constant.
-//
-// #ifdef, etc is absolutely forbidden in this file and highly discouraged
-// in the other vsoc/shm files.
-
-#include <cstdint>
-
-#include "common/vsoc/shm/audio_data_layout.h"
-#include "common/vsoc/shm/e2e_test_region_layout.h"
-#include "common/vsoc/shm/gralloc_layout.h"
-#include "common/vsoc/shm/input_events_layout.h"
-#include "common/vsoc/shm/ril_layout.h"
-#include "common/vsoc/shm/screen_layout.h"
-#include "common/vsoc/shm/socket_forward_layout.h"
-#include "common/vsoc/shm/wifi_exchange_layout.h"
-
-namespace vsoc {
-namespace layout {
-
-template <typename T>
-class VersionInfo {
- public:
- constexpr static size_t size = -1;
-};
-
-// Versioning information for audio_data_layout.h
-// Changes to these structures will affect only the audio_data region
-template <>
-class VersionInfo<audio_data::AudioDataLayout> {
- public:
- // One circular queue of with a 16KB buffer, a 32 bits spinlock and
- // two 32 bits integers.
- constexpr static size_t size = 16384 + 3 * 4;
-};
-
-// Versioning information for e2e_test_region.h
-// Changes to these structures will affect only the e2e_test_region
-template <>
-class VersionInfo<e2e_test::E2EManagerTestRegionLayout> {
- public:
- constexpr static size_t size = 16;
-};
-template <>
-class VersionInfo<e2e_test::E2EPrimaryTestRegionLayout> {
- public:
- constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2ESecondaryTestRegionLayout> {
- public:
- constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2ETestRegionLayout> {
- public:
- constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2EUnfindableRegionLayout> {
- public:
- constexpr static size_t size = 84;
-};
-template <>
-class VersionInfo<e2e_test::E2EManagedTestRegionLayout> {
- public:
- constexpr static size_t size = 4;
-};
-
-// Versioning information for gralloc_layout.h
-// Changes to these structures will affect only the gralloc region
-template <>
-class VersionInfo<gralloc::GrallocManagerLayout> {
- public:
- constexpr static size_t size = 80;
-};
-template <>
-class VersionInfo<gralloc::GrallocBufferLayout> {
- public:
- constexpr static size_t size = 1;
-};
-
-// Versioning information for input_events_layout.h
-// Changes to these structures will affect only the input_events region
-template <>
-class VersionInfo<input_events::InputEventsLayout> {
- public:
- // Three circular queues, each with a 1024 bytes buffer, a 32 bits spinlock
- // and two 32 bits integers.
- constexpr static size_t size = 3 * (1024 + 3 * 4);
-};
-
-// Versioning information for ril_layout.h
-template <>
-class VersionInfo<ril::RilLayout> {
- public:
- constexpr static size_t size = 68;
-};
-
-// Versioning information for screen_layout.h
-// Changes to these structures will affect only the screen region.
-template <>
-class VersionInfo<screen::ScreenLayout> {
- public:
- constexpr static size_t size = 112;
-};
-
-// Versioning Information for socket_forward_layout.h
-template <>
-class VersionInfo<socket_forward::SocketForwardLayout> {
- public:
- constexpr static size_t size = ((((65548 + 4) // queue + state
- * 2) // host_to_guest and guest_to_host
- + 4 + 4) // port and state_lock
- * socket_forward::kNumQueues) +
- 4 // seq_num
- + 4; // generation number
-};
-
-// Versioning information for wifi_layout.h
-template <>
-class VersionInfo<wifi::WifiExchangeLayout> {
- public:
- constexpr static size_t size =
- 65548 + // sizeof(CircularPacketQueue<16, 8192>) - forward
- 65548 + // sizeof(CircularPacketQueue<16, 8192>) - reverse
- 6 + // uint8_t[6] MAC address.
- 6; // uint8_t[6] MAC address.
-};
-
-} // namespace layout
-} // namespace vsoc
diff --git a/common/vsoc/shm/wifi_exchange_layout.h b/common/vsoc/shm/wifi_exchange_layout.h
index 3eaa1b6..df4659e 100644
--- a/common/vsoc/shm/wifi_exchange_layout.h
+++ b/common/vsoc/shm/wifi_exchange_layout.h
@@ -25,6 +25,8 @@
namespace wifi {
struct WifiExchangeLayout : public RegionLayout {
+ static constexpr size_t layout_size = 2 * CircularPacketQueue<16, 8192>::layout_size + 12;
+
// Traffic originating from host that proceeds towards guest.
CircularPacketQueue<16, 8192> guest_ingress;
// Traffic originating from guest that proceeds towards host.
@@ -38,6 +40,8 @@
static const char* region_name;
};
+ASSERT_SHM_COMPATIBLE(WifiExchangeLayout);
+
} // namespace wifi
} // namespace layout
} // namespace vsoc
diff --git a/host/commands/launch/main.cc b/host/commands/launch/main.cc
index bc8371f..c3b2151 100644
--- a/host/commands/launch/main.cc
+++ b/host/commands/launch/main.cc
@@ -35,6 +35,8 @@
#include "common/libs/fs/shared_select.h"
#include "common/libs/strings/str_split.h"
+#include "common/vsoc/lib/vsoc_memory.h"
+#include "common/vsoc/shm/screen_layout.h"
#include "host/commands/launch/pre_launch_initializers.h"
#include "host/libs/config/file_partition.h"
#include "host/libs/config/guest_config.h"
@@ -69,7 +71,12 @@
"The size of the blank data image to generate, MB.");
DEFINE_string(blank_data_image_fmt, "ext4",
"The fs format for the blank data image. Used with mkfs.");
+
DECLARE_int32(dpi);
+DECLARE_int32(x_res);
+DECLARE_int32(y_res);
+DECLARE_int32(num_screen_buffers);
+
DEFINE_bool(disable_app_armor_security, false,
"Disable AppArmor security in libvirt. For debug only.");
DEFINE_bool(disable_dac_security, false,
@@ -86,10 +93,6 @@
"virsh " VIRSH_OPTIONS_PLACEHOLDER " create /dev/fd/0",
"Command to start an instance. If <virsh_options> is present it "
"will be replaced by options to the virsh command");
-DEFINE_string(layout,
- StringFromEnv("ANDROID_HOST_OUT", StringFromEnv("HOME", ".")) +
- "/config/vsoc_mem.json",
- "Location of the vsoc_mem.json file.");
DEFINE_bool(log_xml, false, "Log the XML machine configuration");
DEFINE_int32(memory_mb, 2048,
"Total amount of memory available for guest, MB.");
@@ -148,23 +151,6 @@
return std::string("-c ").append(FLAGS_hypervisor_uri);
}
-Json::Value LoadLayoutFile(const std::string& file) {
- char real_file_path[PATH_MAX];
- if (realpath(file.c_str(), real_file_path) == nullptr) {
- LOG(FATAL) << "Could not get real path for file " << file << ": "
- << strerror(errno);
- }
-
- Json::Value result;
- Json::Reader reader;
- std::ifstream ifs(real_file_path);
- if (!reader.parse(ifs, result)) {
- LOG(FATAL) << "Could not read layout file " << file << ": "
- << reader.getFormattedErrorMessages();
- }
- return result;
-}
-
// VirtualUSBManager manages virtual USB device presence for Cuttlefish.
class VirtualUSBManager {
public:
@@ -210,11 +196,10 @@
// Cuttlefish and host-side daemons.
class IVServerManager {
public:
- IVServerManager(const Json::Value& json_root)
- : server_(ivserver::IVServerOptions(FLAGS_layout, FLAGS_mempath,
+ IVServerManager()
+ : server_(ivserver::IVServerOptions(FLAGS_mempath,
FLAGS_qemusocket,
- vsoc::GetDomain()),
- json_root) {}
+ vsoc::GetDomain())) {}
~IVServerManager() = default;
@@ -484,8 +469,6 @@
FLAGS_vendor_image = FLAGS_system_image_dir + "/vendor.img";
}
- Json::Value json_root = LoadLayoutFile(FLAGS_layout);
-
// Each of these calls is free to fail and terminate launch if file does not
// exist or could not be created.
auto system_partition = config::FilePartition::ReuseExistingFile(
@@ -511,6 +494,7 @@
}
std::string entropy_source = "/dev/urandom";
+ auto& memory_layout = *vsoc::VSoCMemoryLayout::Get();
config::GuestConfig cfg;
cfg.SetID(FLAGS_instance)
@@ -520,7 +504,7 @@
.SetInitRDName(FLAGS_initrd)
.SetKernelArgs(cmdline.str())
.SetIVShMemSocketPath(FLAGS_qemusocket)
- .SetIVShMemVectorCount(json_root["vsoc_device_regions"].size())
+ .SetIVShMemVectorCount(memory_layout.GetRegions().size())
.SetSystemPartitionPath(system_partition->GetName())
.SetCachePartitionPath(cache_partition->GetName())
.SetDataPartitionPath(data_partition->GetName())
@@ -545,7 +529,23 @@
VirtualUSBManager vadb(cfg.GetUSBV1SocketName(), FLAGS_vhci_port,
GetPerInstanceDefault("android_usbip"));
vadb.Start();
- IVServerManager ivshmem(json_root);
+
+ // TODO(b/79170615) These values need to go to the config object/file and the
+ // region resizing be done by the ivserver process (or maybe the config
+ // library to ensure all processes have the correct value?)
+ size_t screen_size =
+ memory_layout
+ .GetRegionByName(vsoc::layout::screen::ScreenLayout::region_name)
+ ->region_size();
+ auto actual_width = ((FLAGS_x_res * 4) + 15) & ~15; // aligned to 16
+ screen_size += FLAGS_num_screen_buffers *
+ (actual_width * FLAGS_y_res + 16 /* padding */);
+ screen_size += (FLAGS_num_screen_buffers - 1) * 4096; /* Guard pages */
+ memory_layout.ResizeRegion(vsoc::layout::screen::ScreenLayout::region_name,
+ screen_size);
+ // TODO(b/79170615) Resize gralloc region too.
+
+ IVServerManager ivshmem;
ivshmem.Start();
KernelLogMonitor kmon(cfg.GetKernelLogSocketName(),
GetDefaultPerInstancePath("kernel.log"),
diff --git a/host/commands/launch/screen_region_handler.cc b/host/commands/launch/screen_region_handler.cc
index 5844537..4214482 100644
--- a/host/commands/launch/screen_region_handler.cc
+++ b/host/commands/launch/screen_region_handler.cc
@@ -25,12 +25,13 @@
DEFINE_int32(y_res, 1280, "Height of the screen in pixels");
DEFINE_int32(dpi, 160, "Pixels per inch for the screen");
DEFINE_int32(refresh_rate_hz, 60, "Screen refresh rate in Hertz");
+DEFINE_int32(num_screen_buffers, 3, "The number of screen buffers");
void InitializeScreenRegion() {
auto region =
vsoc::screen::ScreenRegionView::GetInstance(vsoc::GetDomain().c_str());
if (!region) {
- LOG(ERROR) << "Framebuffer region was not found";
+ LOG(ERROR) << "Screen region was not found";
return;
}
auto dest = region->data();
diff --git a/host/config/Android.mk b/host/config/Android.mk
index 908c90d..59298fc 100644
--- a/host/config/Android.mk
+++ b/host/config/Android.mk
@@ -19,14 +19,6 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE := vsoc_mem_json
-LOCAL_MODULE_CLASS := ETC
-LOCAL_MODULE_PATH := $(HOST_OUT)/config
-LOCAL_MODULE_STEM := vsoc_mem.json
-LOCAL_SRC_FILES := vsoc_mem.json
-include $(BUILD_PREBUILT)
-
-include $(CLEAR_VARS)
LOCAL_MODULE := cuttlefish_dtb
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_PATH := $(HOST_OUT)/config
diff --git a/host/config/vsoc_mem.json b/host/config/vsoc_mem.json
deleted file mode 100644
index 4d1a25f..0000000
--- a/host/config/vsoc_mem.json
+++ /dev/null
@@ -1,250 +0,0 @@
-{
- "vsoc_device_regions" : [
- {
- "device_name" : "vsoc_input",
- "__comment" : "Send input events to the guest",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 4096,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
- "num_nodes_lg2" : 0
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 0
- }
- },
-
- {
- "device_name" : "hwcomposer",
- "__comment" : "HWComposer related",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 16384,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
- {
- "device_name" : "input_events",
- "__comment" : "Send input events from host to guest",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size": 4096,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
- {
- "device_name" : "screen",
- "__comment" : "The screen region.",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size": 12292096,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
- {
- "device_name" : "gralloc_manager",
- "__comment" : "Manages allocation of gralloc buffers",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size" : 40960,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm/lock.h",
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
- {
- "device_name" : "gralloc_memory",
- "__comment" : "Holds the gralloc buffers. Size is 400 MB minus the size of the framebuffer",
- "managed_by" : "gralloc_manager",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size" : 407142400,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm/lock.h",
- "num_nodes_lg2" : 0
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 0
- }
- },
-
- {
- "device_name" : "socket_forward",
- "__comment" : "Holds the data being used by the socket forwarding",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "__comment" : "FIXME this region size is huge until I nail down the correct size",
- "region_size" : 2105344,
-
- "guest_to_host_signal_table" : {
- "__comment" : [
- "sizeof each node is based on common/libs/shm/lock.h",
- "16 spinlocks = 16 * 4 = 64",
- "then the atomic generation number is + 4"
- ],
- "num_nodes_lg2" : 7
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 7
- }
- },
-
- {
- "device_name" : "wifi_exchange",
- "__comment" : [
- "WIFI exchange buffer for primary wireless network interface.",
- "Must be able to accomodate at least one pagesize long packet each direction",
- "Region size = 2 * CircularPacketQueue64k_size + 1024 bytes for control structures."
- ],
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size" : 139264,
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
-
- {
- "device_name" : "ril",
- "__comment" : [
- "Holds initialization values for the ril hal."
- ],
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size" : 4096,
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- },
-
-
- {
- "device_name" : "e2e_primary",
- "__comment" : "Sanity testing",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 16384,
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 1
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 1
- }
- },
-
- {
- "device_name" : "e2e_secondary",
- "__comment" : "Sanity testing",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 16384,
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 1
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 1
- }
- },
-
- {
- "device_name" : "e2e_manager",
- "__comment" : "Sanity testing of managed regions",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 4096,
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 1
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 1
- }
- },
-
- {
- "device_name" : "e2e_managed",
- "__comment" : "Sanity testing of managed regions",
- "current_version" : 1,
- "min_compatible_version" : 1,
- "region_size" : 16384,
- "managed_by" : "e2e_manager",
-
- "guest_to_host_signal_table" : {
- "num_nodes_lg2" : 1
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 1
- }
- },
-
- {
- "device_name" : "audio_data",
- "__comment" : "Write audio HAL output data to ringbuffer",
- "current_version" : 0,
- "min_compatible_version" : 0,
- "region_size": 20480,
-
- "guest_to_host_signal_table" : {
- "__comment" : "sizeof each node is based on common/libs/shm_compatible/lock.h",
- "num_nodes_lg2" : 2
- },
-
- "host_to_guest_signal_table" : {
- "num_nodes_lg2" : 2
- }
- }
- ]
-}
diff --git a/host/libs/ivserver/Android.bp b/host/libs/ivserver/Android.bp
index bfaafa9..93fa62e 100644
--- a/host/libs/ivserver/Android.bp
+++ b/host/libs/ivserver/Android.bp
@@ -27,6 +27,7 @@
],
shared_libs: [
"libbase",
+ "vsoc_lib",
],
static_libs: [
"libjsoncpp",
@@ -46,6 +47,7 @@
"libcuttlefish_fs",
"cuttlefish_auto_resources",
"libbase",
+ "vsoc_lib",
],
static_libs: [
"libivserver",
diff --git a/host/libs/ivserver/ivserver.cc b/host/libs/ivserver/ivserver.cc
index d966764..eb377ec 100644
--- a/host/libs/ivserver/ivserver.cc
+++ b/host/libs/ivserver/ivserver.cc
@@ -26,9 +26,8 @@
namespace ivserver {
-IVServer::IVServer(const IVServerOptions &options, const Json::Value &json_root)
- : json_root_{json_root},
- vsoc_shmem_(VSoCSharedMemory::New(options.shm_file_path, json_root_)) {
+IVServer::IVServer(const IVServerOptions &options)
+ : vsoc_shmem_(VSoCSharedMemory::New(options.shm_file_path)) {
LOG_IF(WARNING, unlink(options.qemu_socket_path.c_str()) == 0)
<< "Removed existing unix socket: " << options.qemu_socket_path
<< ". We can't confirm yet whether another instance is running.";
diff --git a/host/libs/ivserver/ivserver.h b/host/libs/ivserver/ivserver.h
index ad32d81..70fb39f 100644
--- a/host/libs/ivserver/ivserver.h
+++ b/host/libs/ivserver/ivserver.h
@@ -15,7 +15,6 @@
* limitations under the License.
*/
-#include <json/json.h>
#include <memory>
#include "common/libs/fs/shared_fd.h"
@@ -28,8 +27,9 @@
// new connections.
class IVServer final {
public:
- IVServer(const IVServerOptions &options, const Json::Value &json_root);
+ IVServer(const IVServerOptions &options);
IVServer(const IVServer &) = delete;
+ IVServer& operator=(const IVServer&) = delete;
// Serves incoming client and qemu connection.
// This method should never return.
@@ -39,7 +39,6 @@
void HandleNewClientConnection();
void HandleNewQemuConnection();
- const Json::Value &json_root_;
std::unique_ptr<VSoCSharedMemory> vsoc_shmem_;
cvd::SharedFD qemu_channel_;
cvd::SharedFD client_channel_;
diff --git a/host/libs/ivserver/options.cc b/host/libs/ivserver/options.cc
index 25f88dd..56c3dce 100644
--- a/host/libs/ivserver/options.cc
+++ b/host/libs/ivserver/options.cc
@@ -17,18 +17,15 @@
namespace ivserver {
-IVServerOptions::IVServerOptions(const std::string &mem_layout_conf,
- const std::string &shm_file_path,
+IVServerOptions::IVServerOptions(const std::string &shm_file_path,
const std::string &qemu_socket_path,
const std::string &client_socket_path)
- : memory_layout_conf_path(mem_layout_conf),
- shm_file_path(shm_file_path),
+ : shm_file_path(shm_file_path),
qemu_socket_path(qemu_socket_path),
client_socket_path(client_socket_path) {}
std::ostream &operator<<(std::ostream &out, const IVServerOptions &options) {
- out << "\nmem_layout_conf_path: " << options.memory_layout_conf_path
- << "\nshm_file: " << options.shm_file_path
+ out << "\nshm_file: " << options.shm_file_path
<< "\nqemu_socket_path: " << options.qemu_socket_path
<< "\nclient_socket_path: " << options.client_socket_path << std::endl;
diff --git a/host/libs/ivserver/options.h b/host/libs/ivserver/options.h
index 53a51e2..40b3246 100644
--- a/host/libs/ivserver/options.h
+++ b/host/libs/ivserver/options.h
@@ -24,14 +24,12 @@
const uint16_t kIVServerMajorVersion = 1;
const uint16_t kIVServerMinorVersion = 0;
const uint32_t kIVServerDefaultShmSizeInMiB = 4;
-const std::string kIVServerDefaultLayoutFile = "vsoc_mem.json";
//
// structure that contains the various options to start the server.
//
struct IVServerOptions final {
- IVServerOptions(const std::string &mem_layout_conf,
- const std::string &shm_file_path,
+ IVServerOptions(const std::string &shm_file_path,
const std::string &qemu_socket_path,
const std::string &client_socket_path);
@@ -41,7 +39,6 @@
friend std::ostream &operator<<(std::ostream &out,
const IVServerOptions &opts);
- const std::string memory_layout_conf_path;
const std::string shm_file_path;
const std::string qemu_socket_path;
const std::string client_socket_path;
diff --git a/host/libs/ivserver/qemu_client.cc b/host/libs/ivserver/qemu_client.cc
index 2771e06..e3a5cde 100644
--- a/host/libs/ivserver/qemu_client.cc
+++ b/host/libs/ivserver/qemu_client.cc
@@ -81,7 +81,7 @@
for (const auto region_data : shmem.Regions()) {
if (!SendSocketInfo(QemuFDMsg::kHostSideHald, region_data.host_fd)) {
LOG(ERROR) << "Failed to send Host Side FD for region "
- << region_data.values.device_name << ": " << client_socket_->StrError();
+ << region_data.device_name << ": " << client_socket_->StrError();
return false;
}
}
@@ -95,7 +95,7 @@
for (const auto region_data : shmem.Regions()) {
if (!SendSocketInfo(QemuFDMsg::kGuestSideHal, region_data.guest_fd)) {
LOG(ERROR) << "Failed to send Guest Side FD for region "
- << region_data.values.device_name << ": " << client_socket_->StrError();
+ << region_data.device_name << ": " << client_socket_->StrError();
return false;
}
}
diff --git a/host/libs/ivserver/vsocsharedmem.cc b/host/libs/ivserver/vsocsharedmem.cc
index 952c0fe..080ad20 100644
--- a/host/libs/ivserver/vsocsharedmem.cc
+++ b/host/libs/ivserver/vsocsharedmem.cc
@@ -29,64 +29,15 @@
#include <glog/logging.h>
+#include "common/vsoc/lib/vsoc_memory.h"
#include "uapi/vsoc_shm.h"
namespace ivserver {
namespace {
-static_assert(CURRENT_VSOC_LAYOUT_MAJOR_VERSION == 2,
- "Region layout code must be updated");
-
-// Field names from the json file. These are declared so the compiler will
-// catch typos.
-const char g_vsoc_device_regions[] = "vsoc_device_regions";
-const char g_device_name_tag[] = "device_name";
-const char g_managed_by_tag[] = "managed_by";
-
-class RegionAllocator {
- public:
- static uint32_t PageSize() {
- static long page_size = sysconf(_SC_PAGESIZE);
- return page_size;
- }
-
- explicit RegionAllocator(const std::string &name, uint32_t max_size,
- uint32_t offset = 0)
- : name_{name}, max_size_{max_size}, offset_{offset} {}
-
- uint32_t Allocate(uint32_t size, const char *usage, bool *error) {
- if (size > (max_size_ - offset_)) {
- *error = true;
- LOG(ERROR) << name_ << ":"
- << "allocation of " << size << "bytes for " << usage
- << " will overflow memory region";
- }
-
- offset_ += size;
- return (offset_ - size);
- }
-
- void PadTo(uint32_t size, bool *error) {
- uint32_t padding = ((offset_ + (size - 1)) / size) * size - offset_;
- Allocate(padding, "padding", error);
- }
-
- uint32_t AllocateRest(bool *error) {
- return Allocate(max_size_ - offset_, "rest of region", error);
- }
-
- uint32_t GetOffset() const { return offset_; }
-
- private:
- std::string name_;
- uint32_t max_size_;
- uint32_t offset_;
-};
-
class VSoCSharedMemoryImpl : public VSoCSharedMemory {
public:
- VSoCSharedMemoryImpl(const vsoc_shm_layout_descriptor &header,
- const std::map<std::string, size_t> &name_to_region_idx,
+ VSoCSharedMemoryImpl(const std::map<std::string, size_t> &name_to_region_idx,
const std::vector<Region> ®ions,
const std::string &path);
@@ -101,7 +52,6 @@
private:
void CreateLayout();
- const vsoc_shm_layout_descriptor &header_;
cvd::SharedFD shared_mem_fd_;
const std::map<std::string, size_t> region_name_to_index_;
const std::vector<Region> region_data_;
@@ -111,11 +61,9 @@
};
VSoCSharedMemoryImpl::VSoCSharedMemoryImpl(
- const vsoc_shm_layout_descriptor &header,
const std::map<std::string, size_t> &name_to_region_idx,
const std::vector<Region> ®ions, const std::string &path)
- : header_{header},
- region_name_to_index_{name_to_region_idx},
+ : region_name_to_index_{name_to_region_idx},
region_data_{regions} {
// TODO(ender): Lock the file after creation and check lock status upon second
// execution attempt instead of throwing an error.
@@ -127,7 +75,8 @@
LOG_IF(FATAL, !shared_mem_fd_->IsOpen())
<< "Error in creating shared_memory file: " << shared_mem_fd_->StrError();
- int truncate_res = shared_mem_fd_->Truncate(header_.size);
+ int truncate_res = shared_mem_fd_->Truncate(
+ vsoc::VSoCMemoryLayout::Get()->GetMemoryFileSize());
LOG_IF(FATAL, truncate_res == -1)
<< "Error in sizing up the shared memory file: "
<< shared_mem_fd_->StrError();
@@ -144,18 +93,13 @@
}
void VSoCSharedMemoryImpl::CreateLayout() {
- void *mmap_addr = shared_mem_fd_->Mmap(0, header_.size,
- PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+ auto mmap_length = vsoc::VSoCMemoryLayout::Get()->GetMemoryFileSize();
+ void *mmap_addr = shared_mem_fd_->Mmap(0, mmap_length, PROT_READ | PROT_WRITE,
+ MAP_SHARED, 0);
LOG_IF(FATAL, mmap_addr == MAP_FAILED)
<< "Error mmaping file: " << strerror(errno);
- *reinterpret_cast<vsoc_shm_layout_descriptor *>(mmap_addr) = header_;
- auto region_dest = reinterpret_cast<vsoc_device_region *>(
- reinterpret_cast<uintptr_t>(mmap_addr) + header_.vsoc_region_desc_offset);
-
- for (const auto ®ion : region_data_) {
- *region_dest++ = region.values;
- }
- munmap(mmap_addr, header_.size);
+ vsoc::VSoCMemoryLayout::Get()->WriteLayout(mmap_addr);
+ munmap(mmap_addr, mmap_length);
}
bool VSoCSharedMemoryImpl::GetEventFdPairForRegion(
@@ -169,186 +113,42 @@
return true;
}
-template <typename T>
-void GetMandatoryUInt(const std::string ®ion_name,
- const Json::Value &json_region, const char *field_name,
- bool *error, T *dest) {
- if (!json_region.isMember(field_name)) {
- LOG(ERROR) << region_name << " missing " << field_name << " field";
- *error = true;
- return;
- }
- if (!json_region[field_name].isNumeric()) {
- LOG(ERROR) << region_name << " " << field_name << " is not numeric";
- *error = true;
- return;
- }
- *dest = json_region[field_name].asUInt();
-}
-
-void JSONToSignalTable(const std::string ®ion_name,
- const Json::Value &json_region, const char *table_name,
- RegionAllocator *allocator, bool *error,
- vsoc_signal_table_layout *dest) {
- if (!json_region.isMember(table_name)) {
- LOG(ERROR) << region_name << " has no " << table_name << " section";
- *error = true;
- return;
- }
- GetMandatoryUInt(region_name, json_region[table_name], "num_nodes_lg2", error,
- &dest->num_nodes_lg2);
- dest->futex_uaddr_table_offset = allocator->Allocate(
- (1 << dest->num_nodes_lg2) * sizeof(uint32_t), "node table", error);
- dest->interrupt_signalled_offset =
- allocator->Allocate(sizeof(uint32_t), "signal word", error);
-}
-
-std::shared_ptr<VSoCSharedMemory::Region> JSONToRegion(
- const std::string ®ion_name, const Json::Value &json_region,
- bool *failed) {
- std::shared_ptr<VSoCSharedMemory::Region> region(
- new VSoCSharedMemory::Region);
- GetMandatoryUInt(region_name, json_region, "current_version", failed,
- ®ion->values.current_version);
- GetMandatoryUInt(region_name, json_region, "min_compatible_version", failed,
- ®ion->values.min_compatible_version);
- GetMandatoryUInt(region_name, json_region, "region_size", failed,
- ®ion->values.region_end_offset);
- RegionAllocator allocator(region_name, region->values.region_end_offset);
- JSONToSignalTable(region_name, json_region, "guest_to_host_signal_table",
- &allocator, failed,
- ®ion->values.guest_to_host_signal_table);
- JSONToSignalTable(region_name, json_region, "host_to_guest_signal_table",
- &allocator, failed,
- ®ion->values.host_to_guest_signal_table);
-
- region->values.offset_of_region_data = allocator.AllocateRest(failed);
- return region;
-}
-
} // anonymous namespace
std::unique_ptr<VSoCSharedMemory> VSoCSharedMemory::New(
- const std::string &path, const Json::Value &root) {
- // This is so catastrophic that there isn't anything else to check.
- if (!root.isMember(g_vsoc_device_regions)) {
- LOG(ERROR) << "vsoc_device_regions section is absent";
- return nullptr;
- }
- auto device_regions = root[g_vsoc_device_regions];
- bool failed = false;
- RegionAllocator shm_file("shared_memory_file", UINT32_MAX);
- vsoc_shm_layout_descriptor header{};
- header.major_version = CURRENT_VSOC_LAYOUT_MAJOR_VERSION;
- header.minor_version = CURRENT_VSOC_LAYOUT_MINOR_VERSION;
- // size is handled at N1
- header.region_count = device_regions.size();
- shm_file.Allocate(sizeof(header), "header", &failed);
- header.vsoc_region_desc_offset =
- shm_file.Allocate(sizeof(vsoc_device_region) * header.region_count,
- "region descriptors", &failed);
- // Align to a page boundary for the first region
- shm_file.PadTo(RegionAllocator::PageSize(), &failed);
+ const std::string &path) {
+ auto device_layout = vsoc::VSoCMemoryLayout::Get();
std::map<std::string, size_t> name_to_region_idx;
std::vector<Region> regions;
- regions.reserve(header.region_count);
- std::map<std::string, std::string> managed_by_references;
+ regions.reserve(device_layout->GetRegions().size());
- // Pass 1: Parse individual region structures validating all of the
- // fields that can be validated without help.
- for (const auto &json_region : device_regions) {
- if (!json_region.isMember(g_device_name_tag)) {
- LOG(ERROR) << g_device_name_tag << " is missing from region";
- failed = true;
- continue;
- }
- const std::string device_name = json_region[g_device_name_tag].asString();
- if (name_to_region_idx.count(device_name)) {
- LOG(ERROR) << device_name << " used for more than one region";
- failed = true;
- continue;
- }
- std::shared_ptr<Region> region =
- JSONToRegion(device_name, json_region, &failed);
+ for (auto region_spec : device_layout->GetRegions()) {
+ auto device_name = region_spec->region_name();
+
// Create one pair of eventfds for this region. Note that the guest to host
// eventfd is non-blocking, whereas the host to guest eventfd is blocking.
// This is in anticipation of blocking semantics for the host side locks.
- region->host_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
- if (!region->host_fd->IsOpen()) {
- failed = true;
+ auto host_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
+ if (!host_fd->IsOpen()) {
LOG(ERROR) << "Failed to create host eventfd for " << device_name << ": "
- << region->host_fd->StrError();
+ << host_fd->StrError();
+ return nullptr;
}
- region->guest_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
- if (!region->guest_fd->IsOpen()) {
- failed = true;
+ auto guest_fd = cvd::SharedFD::Event(0, EFD_NONBLOCK);
+ if (!guest_fd->IsOpen()) {
LOG(ERROR) << "Failed to create guest eventfd for " << device_name << ": "
- << region->guest_fd->StrError();
- }
- region->values.region_begin_offset = shm_file.Allocate(
- region->values.region_end_offset, device_name.c_str(), &failed);
- shm_file.PadTo(RegionAllocator::PageSize(), &failed);
- region->values.region_end_offset = shm_file.GetOffset();
- if (sizeof(region->values.device_name) - device_name.size() < 1) {
- LOG(ERROR) << device_name << " is too long for a region name";
- failed = true;
- } else {
- strcpy(region->values.device_name, device_name.c_str());
+ << guest_fd->StrError();
+ return nullptr;
}
- name_to_region_idx[device_name] = regions.size();
- regions.push_back(*region);
- // We will attempt to resolve this link in Pass 2
- if (json_region.isMember(g_managed_by_tag)) {
- managed_by_references[device_name] =
- json_region[g_managed_by_tag].asString();
- }
+ auto region_idx = regions.size();
+ name_to_region_idx[device_name] = region_idx;
+ regions.emplace_back(device_name, host_fd, guest_fd);
}
- // Pass 2: Resolve the managed_by_references
- for (const auto &it : managed_by_references) {
- if (!name_to_region_idx.count(it.second)) {
- LOG(ERROR) << it.first << " managed by missing region " << it.second;
- failed = true;
- continue;
- }
- regions[name_to_region_idx[it.first]].values.managed_by =
- name_to_region_idx[it.second];
- if (regions[name_to_region_idx[it.first]].values.managed_by ==
- VSOC_REGION_WHOLE) {
- LOG(ERROR)
- << "Region '" << it.first << "' has owner " << it.second
- << " with index "
- << regions[name_to_region_idx[it.first]].values.managed_by
- << " which is the default value for regions without an owner. Choose"
- "a different region to be at index "
- << regions[name_to_region_idx[it.first]].values.managed_by
- << ", make sure the chosen region is NOT the owner of any other "
- "region";
- }
- }
- if (failed) {
- return nullptr;
- }
- // Handles size (marker N1)
- // The size must be a power of 2
- size_t temp = shm_file.GetOffset();
- size_t allocated_size = 0;
- // Find the highest set bit
- while(temp) {
- allocated_size = temp;
- // Clear a bit
- temp = temp & (temp -1);
- }
- // If the size is already a power of 2 just use it. Otherswise use the
- // next higher power of 2
- if (allocated_size < shm_file.GetOffset()) {
- allocated_size *= 2;
- }
- header.size = allocated_size;
return std::unique_ptr<VSoCSharedMemory>(
- new VSoCSharedMemoryImpl(header, name_to_region_idx, regions, path));
+ new VSoCSharedMemoryImpl(name_to_region_idx, regions, path));
}
} // namespace ivserver
diff --git a/host/libs/ivserver/vsocsharedmem.h b/host/libs/ivserver/vsocsharedmem.h
index f732f6b..613c6a0 100644
--- a/host/libs/ivserver/vsocsharedmem.h
+++ b/host/libs/ivserver/vsocsharedmem.h
@@ -16,10 +16,10 @@
*/
#include <inttypes.h>
-#include <json/json.h>
#include <map>
#include <memory>
#include <string>
+#include <vector>
#include "common/libs/fs/shared_fd.h"
#include "uapi/vsoc_shm.h"
@@ -30,7 +30,11 @@
public:
// Region describes a VSoCSharedMem region.
struct Region {
- vsoc_device_region values{};
+ Region() = default;
+ explicit Region(const char *device_name, const cvd::SharedFD &host_fd,
+ const cvd::SharedFD &guest_fd)
+ : device_name(device_name), host_fd(host_fd), guest_fd(guest_fd) {}
+ const char *device_name;
cvd::SharedFD host_fd;
cvd::SharedFD guest_fd;
};
@@ -38,8 +42,7 @@
VSoCSharedMemory() = default;
virtual ~VSoCSharedMemory() = default;
- static std::unique_ptr<VSoCSharedMemory> New(const std::string &name,
- const Json::Value &json_root);
+ static std::unique_ptr<VSoCSharedMemory> New(const std::string &name);
virtual bool GetEventFdPairForRegion(const std::string ®ion_name,
cvd::SharedFD *guest_to_host,