[release] Snap to 82089872a3
Change-Id: I40b95c5d1e87654ba539a30934e923e268f971e4
diff --git a/src/developer/ffx/src/main.rs b/src/developer/ffx/src/main.rs
index 40a4b50..63235c3 100644
--- a/src/developer/ffx/src/main.rs
+++ b/src/developer/ffx/src/main.rs
@@ -13,7 +13,7 @@
fidl::endpoints::create_proxy,
fidl_fuchsia_developer_bridge::{DaemonError, DaemonProxy, FastbootMarker, FastbootProxy},
fidl_fuchsia_developer_remotecontrol::{RemoteControlMarker, RemoteControlProxy},
- futures::try_join,
+ fuchsia_async::TimeoutExt,
lazy_static::lazy_static,
std::sync::{Arc, Mutex},
std::time::Duration,
@@ -115,7 +115,7 @@
false
}
-async fn run() -> Result<((), ())> {
+async fn run() -> Result<()> {
let app: Ffx = argh::from_env();
// Configuration initialization must happen before ANY calls to the config (or the cache won't
@@ -133,24 +133,34 @@
let notice_writer = Box::new(std::io::stderr());
show_analytics_notice(notice_writer);
- let args: Vec<String> = std::env::args().collect();
- // drop arg[0]: executable with hard path
- // TODO do we want to break out subcommands for analytics?
- let args_str = &args[1..].join(" ");
- let launch_args = format!("{}", &args_str);
- let build_info = build_info();
- let build_version = build_info.build_version.as_deref();
- try_join!(
- add_launch_event(APP_NAME, build_version, Some(&launch_args)),
- ffx_lib_suite::ffx_plugin_impl(
- get_daemon_proxy,
- get_remote_proxy,
- get_fastboot_proxy,
- is_experiment_subcommand_on,
- app,
- )
+ let analytics_task = fuchsia_async::Task::spawn(async {
+ let args: Vec<String> = std::env::args().collect();
+ // drop arg[0]: executable with hard path
+ // TODO do we want to break out subcommands for analytics?
+ let args_str = &args[1..].join(" ");
+ let launch_args = format!("{}", &args_str);
+ let build_info = build_info();
+ let build_version = build_info.build_version;
+ add_launch_event(APP_NAME, build_version.as_deref(), Some(launch_args).as_deref()).await
+ });
+ let res = ffx_lib_suite::ffx_plugin_impl(
+ get_daemon_proxy,
+ get_remote_proxy,
+ get_fastboot_proxy,
+ is_experiment_subcommand_on,
+ app,
)
+ .await;
+ let _ = analytics_task
+ // TODO(66918): make configurable, and evaluate chosen time value.
+ .on_timeout(Duration::from_secs(2), || {
+ log::error!("analytics submission timed out");
+ // Analytics timeouts should not impact user flows
+ Ok(())
+ })
+ .await;
+ res
}
#[fuchsia_async::run_singlethreaded]
@@ -167,8 +177,16 @@
eprintln!("BUG: An internal command error occurred.\n{:?}", err);
}
let err_msg = format!("{}", err);
- add_crash_event(&err_msg).await.unwrap(); // unwrap because return is always empty and
- // users can't act on analytics failures
+ // TODO(66918): make configurable, and evaluate chosen time value.
+ if let Err(e) = add_crash_event(&err_msg)
+ .on_timeout(Duration::from_secs(2), || {
+ log::error!("analytics timed out reporting crash event");
+ Ok(())
+ })
+ .await
+ {
+ log::error!("analytics failed to submit crash event: {}", e);
+ }
std::process::exit(1);
}
}
diff --git a/src/lib/analytics/rust/src/lib.rs b/src/lib/analytics/rust/src/lib.rs
index aec6e66..47cb93d 100644
--- a/src/lib/analytics/rust/src/lib.rs
+++ b/src/lib/analytics/rust/src/lib.rs
@@ -41,7 +41,7 @@
let body = make_body_with_hash(&app_name, app_version, args);
let client = new_https_client();
- let req = Request::builder().method(Method::POST).uri(GA_URL).body(Body::from(body)).unwrap();
+ let req = Request::builder().method(Method::POST).uri(GA_URL).body(Body::from(body))?;
let mut res = client.request(req).await;
match res {
Ok(res) => log::info!("Analytics response: {}", res.status()),
diff --git a/src/lib/fidl/llcpp/tests/protocol_test.cc b/src/lib/fidl/llcpp/tests/protocol_test.cc
index 62d64c1..8991408 100644
--- a/src/lib/fidl/llcpp/tests/protocol_test.cc
+++ b/src/lib/fidl/llcpp/tests/protocol_test.cc
@@ -385,3 +385,29 @@
EmptyImpl server;
fidl::BindServer(loop.dispatcher(), std::move(server_end), &server);
}
+
+// Test creating a typed channel endpoint pair.
+TEST(Endpoints, CreateFromProtocol) {
+ // `std::move` pattern
+ {
+ auto endpoints = fidl::CreateEndpoints<test::Empty>();
+ ASSERT_TRUE(endpoints.is_ok());
+ ASSERT_EQ(ZX_OK, endpoints.status_value()) << endpoints.status_string();
+ fidl::ClientEnd<test::Empty> client_end = std::move(endpoints->client);
+ fidl::ServerEnd<test::Empty> server_end = std::move(endpoints->server);
+
+ ASSERT_TRUE(client_end.is_valid());
+ ASSERT_TRUE(server_end.is_valid());
+ }
+
+ // Destructuring pattern
+ {
+ auto endpoints = fidl::CreateEndpoints<test::Empty>();
+ ASSERT_TRUE(endpoints.is_ok());
+ ASSERT_EQ(ZX_OK, endpoints.status_value()) << endpoints.status_string();
+ auto [client_end, server_end] = std::move(endpoints.value());
+
+ ASSERT_TRUE(client_end.is_valid());
+ ASSERT_TRUE(server_end.is_valid());
+ }
+}
diff --git a/src/sys/lib/library_loader/BUILD.gn b/src/sys/lib/library_loader/BUILD.gn
index b4ce7f9..cdef3b2 100644
--- a/src/sys/lib/library_loader/BUILD.gn
+++ b/src/sys/lib/library_loader/BUILD.gn
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-import("//build/package.gni")
+import("//build/dist/resource.gni")
import("//build/rust/rustc_library.gni")
-import("//build/test/test_package.gni")
import("//build/testing/environments.gni")
+import("//src/sys/build/components.gni")
rustc_library("library_loader") {
version = "0.1.0"
@@ -34,30 +34,26 @@
# files using OPEN_RIGHT_EXECUTABLE/VMO_FLAG_EXEC, and the easiest way to provide a test directory
# that supports that is a real pkgfs directory.
# TODO(fxbug.dev/37534): Remove this once Rust vfs supports OPEN_RIGHT_EXECUTABLE
-generate_manifest("config_test_files") {
- args = [
- "--entry=lib/config_test/foo=" +
- rebase_path("config_test_files/foo", root_build_dir),
- "--entry=lib/config_test/bar/baz=" +
- rebase_path("config_test_files/bar/baz", root_build_dir),
- ]
+resource("config_test_foo") {
+ sources = [ "config_test_files/foo" ]
+ outputs = [ "lib/config_test/foo" ]
}
-test_package("library_loader_tests") {
+resource("config_test_bar_baz") {
+ sources = [ "config_test_files/bar/baz" ]
+ outputs = [ "lib/config_test/bar/baz" ]
+}
+
+fuchsia_unittest_package("library_loader_tests") {
deps = [
- ":config_test_files",
+ ":config_test_bar_baz",
+ ":config_test_foo",
":library_loader_test",
]
-
- extra = get_target_outputs(":config_test_files")
-
- tests = [
- {
- name = "library_loader_lib_test"
- dest = "library_loader_tests"
- environments = basic_envs
- },
- ]
+ manifest = "meta/library_loader_tests.cmx"
+ test_specs = {
+ environments = basic_envs
+ }
}
group("tests") {
diff --git a/src/sys/lib/library_loader/meta/library_loader_tests.cmx b/src/sys/lib/library_loader/meta/library_loader_tests.cmx
index e41c6945..e5c8b70 100644
--- a/src/sys/lib/library_loader/meta/library_loader_tests.cmx
+++ b/src/sys/lib/library_loader/meta/library_loader_tests.cmx
@@ -3,6 +3,6 @@
"sdk/lib/diagnostics/syslog/client.shard.cmx"
],
"program": {
- "binary": "test/library_loader_tests"
+ "binary": "bin/library_loader_lib_test"
}
}
diff --git a/src/sys/pkg/tests/system-tests/README.md b/src/sys/pkg/tests/system-tests/README.md
index 0fa387a..b10ec5c 100644
--- a/src/sys/pkg/tests/system-tests/README.md
+++ b/src/sys/pkg/tests/system-tests/README.md
@@ -154,7 +154,7 @@
```
% fx set ... \
--with //src/sys/pkg:tests \
- --args 'kernel_cmdline_args=["kernel.serial=legacy"]'
+ --args 'dev_bootfs_labels+=["//src/zircon/kernel/cmdline:serial-legacy"]'
% fx build
```
diff --git a/src/tests/benchmarks/fidl/reference/BUILD.gn b/src/tests/benchmarks/fidl/reference/BUILD.gn
index a0e6918..b3d0da4 100644
--- a/src/tests/benchmarks/fidl/reference/BUILD.gn
+++ b/src/tests/benchmarks/fidl/reference/BUILD.gn
@@ -40,7 +40,6 @@
"//zircon/public/lib/fidl",
"//zircon/public/lib/sync",
"//zircon/system/ulib/perftest",
- benchmark_suite_fidl_target,
]
}
diff --git a/src/zircon/kernel/cmdline/BUILD.gn b/src/zircon/kernel/cmdline/BUILD.gn
new file mode 100644
index 0000000..ca6f2b2
--- /dev/null
+++ b/src/zircon/kernel/cmdline/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2020 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/zbi/kernel_cmdline.gni")
+
+kernel_cmdline("serial-legacy") {
+ args = [ "kernel.serial=legacy" ]
+}
diff --git a/src/zircon/kernel/cmdline/README.md b/src/zircon/kernel/cmdline/README.md
new file mode 100644
index 0000000..d7182b8
--- /dev/null
+++ b/src/zircon/kernel/cmdline/README.md
@@ -0,0 +1,9 @@
+# Kernel command-line arguments
+
+The build file in this directory contains targets for various options for kernel
+command-line arguments.
+
+These arguments should be passed via the relevant GN arguments:
+- `board_bootfs_labels` (from [`//build/board.gni`](build/board.gni)) in a board file;
+- `product_bootfs_labels` (from [`//build/product.gni`](build/product.gni)) in a product file;
+- `dev_bootfs_labels` (from [`//build/dev.gni`](build/dev.gni)) in an `fx set` and `gn gen` invocation.
diff --git a/tools/fidl/gidl/gidl.gni b/tools/fidl/gidl/gidl.gni
index 569af43..7fa47a6 100644
--- a/tools/fidl/gidl/gidl.gni
+++ b/tools/fidl/gidl/gidl.gni
@@ -103,10 +103,8 @@
source_set(target_name) {
sources = [ output_filename ]
- deps = [
- ":${gidl_target}",
- fidl_bindings,
- ]
+ deps = [ ":${gidl_target}" ]
+ public_deps = [ fidl_bindings ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
diff --git a/zircon/kernel/arch/x86/mp.cc b/zircon/kernel/arch/x86/mp.cc
index c61ad08..a2c831a 100644
--- a/zircon/kernel/arch/x86/mp.cc
+++ b/zircon/kernel/arch/x86/mp.cc
@@ -113,10 +113,10 @@
}
memset(ap_percpus, 0, len);
- use_monitor = arch::BootCpuid<arch::CpuidFeatureFlagsC>().monitor() &&
- (arch::BootCpuid<arch::CpuidMaximumLeaf>().reg_value() >=
- arch::CpuidMonitorMwaitB::kLeaf) &&
- !x86_get_microarch_config()->idle_prefer_hlt;
+ use_monitor =
+ arch::BootCpuid<arch::CpuidFeatureFlagsC>().monitor() &&
+ (arch::BootCpuid<arch::CpuidMaximumLeaf>().leaf() >= arch::CpuidMonitorMwaitB::kLeaf) &&
+ !x86_get_microarch_config()->idle_prefer_hlt;
if (use_monitor) {
uint16_t monitor_size =
arch::BootCpuid<arch::CpuidMonitorMwaitB>().largest_monitor_line_size();
diff --git a/zircon/kernel/arch/x86/perf_mon.cc b/zircon/kernel/arch/x86/perf_mon.cc
index 9c0c3ef..70993e3 100644
--- a/zircon/kernel/arch/x86/perf_mon.cc
+++ b/zircon/kernel/arch/x86/perf_mon.cc
@@ -420,8 +420,7 @@
}
static void x86_perfmon_init_once(uint level) {
- if (arch::BootCpuid<arch::CpuidMaximumLeaf>().reg_value() <
- arch::CpuidPerformanceMonitoringA::kLeaf) {
+ if (arch::BootCpuid<arch::CpuidMaximumLeaf>().leaf() < arch::CpuidPerformanceMonitoringA::kLeaf) {
return;
}
diff --git a/zircon/kernel/arch/x86/proc_trace.cc b/zircon/kernel/arch/x86/proc_trace.cc
index b382847..dd691c5 100644
--- a/zircon/kernel/arch/x86/proc_trace.cc
+++ b/zircon/kernel/arch/x86/proc_trace.cc
@@ -111,7 +111,8 @@
static uint32_t ipt_num_traces TA_GUARDED(IptLock::Get());
void x86_processor_trace_init(void) {
- if (!arch::BootCpuid<arch::CpuidExtendedFeatureFlagsB>().intel_pt()) {
+ if ((arch::BootCpuid<arch::CpuidMaximumLeaf>().leaf() < arch::CpuidProcessorTraceMainB::kLeaf) ||
+ !arch::BootCpuid<arch::CpuidExtendedFeatureFlagsB>().intel_pt()) {
return;
}
diff --git a/zircon/kernel/lib/arch/include/lib/arch/x86/cpuid.h b/zircon/kernel/lib/arch/include/lib/arch/x86/cpuid.h
index 10c90b7..8e64315f 100644
--- a/zircon/kernel/lib/arch/include/lib/arch/x86/cpuid.h
+++ b/zircon/kernel/lib/arch/include/lib/arch/x86/cpuid.h
@@ -47,6 +47,43 @@
uint32_t values_[4];
};
+// Define a "CPUID value type" as any type with the following:
+// * static constexpr uint32_t members, `kLeaf` and `kSubleaf` giving the
+// associated leaf and subleaf;
+// * a static `Get()` method returning a `hwreg::RegisterAddr` object holding
+// an "address" of one of the `CpuidIo::Register` values.
+//
+// CPUID "I/O" providers will deal in such types. See arch::BootCpuidIo and
+// arch::testing::FakeCpuidIo for instances of such contracts.
+//
+// Note: there is no inherent relationship between the CPUID value type and the
+// return type of `Get()`. In practice, a CPUID value type might be precisely
+// the hwreg register type expressing the bit layout or a sort of getter for
+// such a type (the utility of which lies in the fact that hwreg register
+// types cannot be templated, for various reasons).
+//
+// We use Intel's terms of "leaf" and "subleaf" over AMD's "function" and
+// "subfunction" as the latter pair is more overloaded and ambiguous.
+
+// CpuidIoValue is a convenience type for defining a CPUID value type.
+template <typename ValueType, uint32_t Leaf, uint32_t Subleaf, CpuidIo::Register OutputRegister>
+struct CpuidIoValue {
+ static constexpr uint32_t kLeaf = Leaf;
+ static constexpr uint32_t kSubleaf = Subleaf;
+
+ static auto Get() { return hwreg::RegisterAddr<ValueType>(OutputRegister); }
+};
+
+// CpuidIoValueBase is a convenience type for defining both a CPUID value type
+// as well as the associated register type.
+//
+// Assembly macro generation requires the use of `hwreg::EnablePrinter`; to
+// make such use-cases more conveniently accessible - and since the code-gen
+// cost here is rather minimal - we generally use the feature below.
+template <typename ValueType, uint32_t Leaf, uint32_t Subleaf, CpuidIo::Register OutputRegister>
+struct CpuidIoValueBase : public hwreg::RegisterBase<ValueType, uint32_t, hwreg::EnablePrinter>,
+ public CpuidIoValue<ValueType, Leaf, Subleaf, OutputRegister> {};
+
enum class Vendor {
kUnknown,
kIntel,
@@ -92,28 +129,6 @@
std::string_view ToString(Vendor vendor);
std::string_view ToString(Microarchitecture microarch);
-// A convenient and self-documenting wrapper for defining CPUID value bitsets
-// as hwreg register objects, along with their associated leaf and subleaf
-// values (which are always expected to be defined as static constexpr
-// members).
-//
-// We use Intel's terms of "leaf", "subleaf" over AMD's "function", "subfuntion"
-// as the latter pair is more overloaded and ambiguous.
-//
-// Assembly macro generation requires the use of `hwreg::EnablePrinter`.
-//
-// TODO(joshuaseaton|mcgrathr): When global templated CpuidIo objects are
-// defined, also define a templated getter that takes a CpuidValue type,
-// consults kLeaf and kSubleaf, and returns the appropriate object (e.g.,
-// `GetCpuidFor<ValueType>()`).
-template <typename ValueType, uint32_t Leaf, uint32_t Subleaf, CpuidIo::Register OutputRegister>
-struct CpuidValueBase : public hwreg::RegisterBase<ValueType, uint32_t, hwreg::EnablePrinter> {
- static constexpr uint32_t kLeaf = Leaf;
- static constexpr uint32_t kSubleaf = Subleaf;
-
- static auto Get() { return hwreg::RegisterAddr<ValueType>(OutputRegister); }
-};
-
//---------------------------------------------------------------------------//
// Leaf/Function 0x0.
//
@@ -122,21 +137,29 @@
//---------------------------------------------------------------------------//
// [amd/vol3]: E.3.1, CPUID Fn0000_0000_EAX Largest Standard Function Number.
-struct CpuidMaximumLeaf : public CpuidValueBase<CpuidMaximumLeaf, 0x0, 0x0, CpuidIo::kEax> {};
+struct CpuidMaximumLeaf : public CpuidIoValueBase<CpuidMaximumLeaf, 0x0, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, leaf);
+};
// [amd/vol3]: E.3.1, CPUID Fn0000_0000_E[D,C,B]X Processor Vendor.
-struct CpuidVendorB : public CpuidValueBase<CpuidVendorB, 0x0, 0x0, CpuidIo::kEbx> {};
-struct CpuidVendorC : public CpuidValueBase<CpuidVendorC, 0x0, 0x0, CpuidIo::kEcx> {};
-struct CpuidVendorD : public CpuidValueBase<CpuidVendorD, 0x0, 0x0, CpuidIo::kEdx> {};
+struct CpuidVendorB : public CpuidIoValueBase<CpuidVendorB, 0x0, 0x0, CpuidIo::kEbx> {
+ DEF_FIELD(31, 0, value);
+};
+struct CpuidVendorC : public CpuidIoValueBase<CpuidVendorC, 0x0, 0x0, CpuidIo::kEcx> {
+ DEF_FIELD(31, 0, value);
+};
+struct CpuidVendorD : public CpuidIoValueBase<CpuidVendorD, 0x0, 0x0, CpuidIo::kEdx> {
+ DEF_FIELD(31, 0, value);
+};
template <typename CpuidIoProvider>
Vendor GetVendor(CpuidIoProvider&& io) {
using namespace std::string_view_literals;
const uint32_t ids[] = {
- io.template Read<CpuidVendorB>().reg_value(),
- io.template Read<CpuidVendorD>().reg_value(),
- io.template Read<CpuidVendorC>().reg_value(),
+ io.template Read<CpuidVendorB>().value(),
+ io.template Read<CpuidVendorD>().value(),
+ io.template Read<CpuidVendorC>().value(),
};
std::string_view name{reinterpret_cast<const char*>(ids), sizeof(ids)};
if (name == "GenuineIntel"sv) {
@@ -156,7 +179,7 @@
// [intel/vol2]: Figure 3-6. Version Information Returned by CPUID in EAX.
// [amd/vol3]: E.3.2, CPUID Fn0000_0001_EAX Family, Model, Stepping Identifiers.
-struct CpuidVersionInfo : public CpuidValueBase<CpuidVersionInfo, 0x1, 0x0, CpuidIo::kEax> {
+struct CpuidVersionInfo : public CpuidIoValueBase<CpuidVersionInfo, 0x1, 0x0, CpuidIo::kEax> {
// [intel/vol2]: Table 3-9. Processor Type Field.
enum class IntelProcessorType : uint8_t {
kOriginalOem = 0b00,
@@ -191,7 +214,7 @@
// [intel/vol2]: Table 3-10. Feature Information Returned in the ECX Register.
// [amd/vol3]: E.3.2, CPUID Fn0000_0001_ECX Feature Identifiers.
-struct CpuidFeatureFlagsC : public CpuidValueBase<CpuidFeatureFlagsC, 0x1, 0x0, CpuidIo::kEcx> {
+struct CpuidFeatureFlagsC : public CpuidIoValueBase<CpuidFeatureFlagsC, 0x1, 0x0, CpuidIo::kEcx> {
// AMD documented "RAZ. Reserved for use by hypervisor to indicate guest
// status."; Intel documents "Not Used. Always returns 0.".
DEF_BIT(31, hypervisor);
@@ -230,7 +253,7 @@
// [intel/vol2]: Table 3-11. More on Feature Information Returned in the EDX Register.
// [amd/vol3]: E.3.6 Function 7h—Structured Extended Feature Identifiers.
-struct CpuidFeatureFlagsD : public CpuidValueBase<CpuidFeatureFlagsD, 0x1, 0x0, CpuidIo::kEdx> {
+struct CpuidFeatureFlagsD : public CpuidIoValueBase<CpuidFeatureFlagsD, 0x1, 0x0, CpuidIo::kEdx> {
DEF_BIT(31, pbe);
// Bit 30 is reserved.
DEF_BIT(29, tm);
@@ -272,23 +295,23 @@
// [amd/vol3]: E.3.4 Function 5h—Monitor and MWait Features.
//---------------------------------------------------------------------------//
-struct CpuidMonitorMwaitA : public CpuidValueBase<CpuidMonitorMwaitA, 0x5, 0x0, CpuidIo::kEax> {
+struct CpuidMonitorMwaitA : public CpuidIoValueBase<CpuidMonitorMwaitA, 0x5, 0x0, CpuidIo::kEax> {
DEF_RSVDZ_FIELD(31, 16);
DEF_FIELD(15, 0, smallest_monitor_line_size);
};
-struct CpuidMonitorMwaitB : public CpuidValueBase<CpuidMonitorMwaitB, 0x5, 0x0, CpuidIo::kEbx> {
+struct CpuidMonitorMwaitB : public CpuidIoValueBase<CpuidMonitorMwaitB, 0x5, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 16);
DEF_FIELD(15, 0, largest_monitor_line_size);
};
-struct CpuidMonitorMwaitC : public CpuidValueBase<CpuidMonitorMwaitC, 0x5, 0x0, CpuidIo::kEcx> {
+struct CpuidMonitorMwaitC : public CpuidIoValueBase<CpuidMonitorMwaitC, 0x5, 0x0, CpuidIo::kEcx> {
// Bits [31: 2] are reserved.
DEF_BIT(1, ibe);
DEF_BIT(0, emx);
};
-struct CpuidMonitorMwaitD : public CpuidValueBase<CpuidMonitorMwaitD, 0x5, 0x0, CpuidIo::kEdx> {
+struct CpuidMonitorMwaitD : public CpuidIoValueBase<CpuidMonitorMwaitD, 0x5, 0x0, CpuidIo::kEdx> {
DEF_FIELD(31, 28, c7_sub_c_states);
DEF_FIELD(27, 24, c6_sub_c_states);
DEF_FIELD(23, 20, c5_sub_c_states);
@@ -308,7 +331,7 @@
// [amd/vol3]: E.3.6, CPUID Fn0000_0007_EBX_x0 Structured Extended Feature Identifiers (ECX=0).
struct CpuidExtendedFeatureFlagsB
- : public CpuidValueBase<CpuidExtendedFeatureFlagsB, 0x7, 0x0, CpuidIo::kEbx> {
+ : public CpuidIoValueBase<CpuidExtendedFeatureFlagsB, 0x7, 0x0, CpuidIo::kEbx> {
DEF_BIT(31, avx512vl);
DEF_BIT(30, avx512bw);
DEF_BIT(29, sha);
@@ -350,7 +373,7 @@
//---------------------------------------------------------------------------//
struct CpuidPerformanceMonitoringA
- : public CpuidValueBase<CpuidPerformanceMonitoringA, 0xa, 0x0, CpuidIo::kEax> {
+ : public CpuidIoValueBase<CpuidPerformanceMonitoringA, 0xa, 0x0, CpuidIo::kEax> {
DEF_FIELD(31, 24, ebx_vector_length);
DEF_FIELD(23, 16, general_counter_width);
DEF_FIELD(15, 8, num_general_counters);
@@ -358,7 +381,7 @@
};
struct CpuidPerformanceMonitoringB
- : public CpuidValueBase<CpuidPerformanceMonitoringB, 0xa, 0x0, CpuidIo::kEbx> {
+ : public CpuidIoValueBase<CpuidPerformanceMonitoringB, 0xa, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 7);
DEF_BIT(6, branch_mispredict_retired_event_unavailable);
DEF_BIT(5, branch_instruction_retired_event_unavailable);
@@ -370,7 +393,7 @@
};
struct CpuidPerformanceMonitoringD
- : public CpuidValueBase<CpuidPerformanceMonitoringD, 0xa, 0x0, CpuidIo::kEdx> {
+ : public CpuidIoValueBase<CpuidPerformanceMonitoringD, 0xa, 0x0, CpuidIo::kEdx> {
DEF_RSVDZ_FIELD(31, 16);
DEF_BIT(15, anythread_deprecation);
DEF_RSVDZ_FIELD(14, 13);
@@ -385,7 +408,7 @@
//---------------------------------------------------------------------------//
struct CpuidProcessorTraceMainB
- : public CpuidValueBase<CpuidProcessorTraceMainB, 0x14, 0x0, CpuidIo::kEbx> {
+ : public CpuidIoValueBase<CpuidProcessorTraceMainB, 0x14, 0x0, CpuidIo::kEbx> {
DEF_RSVDZ_FIELD(31, 6);
DEF_BIT(5, power_event_trace);
DEF_BIT(4, ptwrite);
@@ -396,7 +419,7 @@
};
struct CpuidProcessorTraceMainC
- : public CpuidValueBase<CpuidProcessorTraceMainC, 0x14, 0x0, CpuidIo::kEcx> {
+ : public CpuidIoValueBase<CpuidProcessorTraceMainC, 0x14, 0x0, CpuidIo::kEcx> {
DEF_BIT(31, lip);
DEF_RSVDZ_FIELD(30, 4);
DEF_BIT(3, trace_transport);
@@ -419,14 +442,22 @@
//---------------------------------------------------------------------------//
struct CpuidMaximumHypervisorLeaf
- : public CpuidValueBase<CpuidMaximumHypervisorLeaf, 0x4000'0000, 0x0, CpuidIo::kEax> {};
+ : public CpuidIoValueBase<CpuidMaximumHypervisorLeaf, 0x4000'0000, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, leaf);
+};
struct CpuidHypervisorNameB
- : public CpuidValueBase<CpuidHypervisorNameB, 0x4000'0000, 0x0, CpuidIo::kEbx> {};
+ : public CpuidIoValueBase<CpuidHypervisorNameB, 0x4000'0000, 0x0, CpuidIo::kEbx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidHypervisorNameC
- : public CpuidValueBase<CpuidHypervisorNameC, 0x4000'0000, 0x0, CpuidIo::kEcx> {};
+ : public CpuidIoValueBase<CpuidHypervisorNameC, 0x4000'0000, 0x0, CpuidIo::kEcx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidHypervisorNameD
- : public CpuidValueBase<CpuidHypervisorNameD, 0x4000'0000, 0x0, CpuidIo::kEdx> {};
+ : public CpuidIoValueBase<CpuidHypervisorNameD, 0x4000'0000, 0x0, CpuidIo::kEdx> {
+ DEF_FIELD(31, 0, value);
+};
// HypervisorName is a simple class that serves to hold the content of a
// hypervisor's name (or "vendor string").
@@ -437,9 +468,9 @@
// Check if we are actually within a hypervisor.
if (io.template Read<CpuidFeatureFlagsC>().hypervisor()) {
const uint32_t values[] = {
- io.template Read<CpuidHypervisorNameB>().reg_value(),
- io.template Read<CpuidHypervisorNameC>().reg_value(),
- io.template Read<CpuidHypervisorNameD>().reg_value(),
+ io.template Read<CpuidHypervisorNameB>().value(),
+ io.template Read<CpuidHypervisorNameC>().value(),
+ io.template Read<CpuidHypervisorNameD>().value(),
};
static_assert(kSize == sizeof(values));
memcpy(str_.data(), values, kSize);
@@ -469,7 +500,9 @@
// [amd/vol3]: CPUID Fn8000_0000_EAX Largest Extended Function Number
struct CpuidMaximumExtendedLeaf
- : public CpuidValueBase<CpuidMaximumExtendedLeaf, 0x8000'0000, 0x0, CpuidIo::kEax> {};
+ : public CpuidIoValueBase<CpuidMaximumExtendedLeaf, 0x8000'0000, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, leaf);
+};
//---------------------------------------------------------------------------//
// Leaves/Functions 0x8000'0002 - 0x8000'0004
@@ -482,31 +515,55 @@
// express (zero-based) index into how the combine to form the processor name
// string.
struct CpuidProcessorName2A
- : public CpuidValueBase<CpuidProcessorName2A, 0x8000'0002, 0x0, CpuidIo::kEax> {};
+ : public CpuidIoValueBase<CpuidProcessorName2A, 0x8000'0002, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName2B
- : public CpuidValueBase<CpuidProcessorName2B, 0x8000'0002, 0x0, CpuidIo::kEbx> {};
+ : public CpuidIoValueBase<CpuidProcessorName2B, 0x8000'0002, 0x0, CpuidIo::kEbx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName2C
- : public CpuidValueBase<CpuidProcessorName2C, 0x8000'0002, 0x0, CpuidIo::kEcx> {};
+ : public CpuidIoValueBase<CpuidProcessorName2C, 0x8000'0002, 0x0, CpuidIo::kEcx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName2D
- : public CpuidValueBase<CpuidProcessorName2D, 0x8000'0002, 0x0, CpuidIo::kEdx> {};
+ : public CpuidIoValueBase<CpuidProcessorName2D, 0x8000'0002, 0x0, CpuidIo::kEdx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName3A
- : public CpuidValueBase<CpuidProcessorName3A, 0x8000'0003, 0x0, CpuidIo::kEax> {};
+ : public CpuidIoValueBase<CpuidProcessorName3A, 0x8000'0003, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName3B
- : public CpuidValueBase<CpuidProcessorName3B, 0x8000'0003, 0x0, CpuidIo::kEbx> {};
+ : public CpuidIoValueBase<CpuidProcessorName3B, 0x8000'0003, 0x0, CpuidIo::kEbx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName3C
- : public CpuidValueBase<CpuidProcessorName3C, 0x8000'0003, 0x0, CpuidIo::kEcx> {};
+ : public CpuidIoValueBase<CpuidProcessorName3C, 0x8000'0003, 0x0, CpuidIo::kEcx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName3D
- : public CpuidValueBase<CpuidProcessorName3D, 0x8000'0003, 0x0, CpuidIo::kEdx> {};
+ : public CpuidIoValueBase<CpuidProcessorName3D, 0x8000'0003, 0x0, CpuidIo::kEdx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName4A
- : public CpuidValueBase<CpuidProcessorName4A, 0x8000'0004, 0x0, CpuidIo::kEax> {};
+ : public CpuidIoValueBase<CpuidProcessorName4A, 0x8000'0004, 0x0, CpuidIo::kEax> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName4B
- : public CpuidValueBase<CpuidProcessorName4B, 0x8000'0004, 0x0, CpuidIo::kEbx> {};
+ : public CpuidIoValueBase<CpuidProcessorName4B, 0x8000'0004, 0x0, CpuidIo::kEbx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName4C
- : public CpuidValueBase<CpuidProcessorName4C, 0x8000'0004, 0x0, CpuidIo::kEcx> {};
+ : public CpuidIoValueBase<CpuidProcessorName4C, 0x8000'0004, 0x0, CpuidIo::kEcx> {
+ DEF_FIELD(31, 0, value);
+};
struct CpuidProcessorName4D
- : public CpuidValueBase<CpuidProcessorName4D, 0x8000'0004, 0x0, CpuidIo::kEdx> {};
+ : public CpuidIoValueBase<CpuidProcessorName4D, 0x8000'0004, 0x0, CpuidIo::kEdx> {
+ DEF_FIELD(31, 0, value);
+};
// ProcessorName is a simple class that serves to hold the content of a
// processor name (or "brand string" in Intel-speak), a general identifier.
@@ -515,20 +572,20 @@
template <typename CpuidIoProvider>
explicit ProcessorName(CpuidIoProvider&& io) {
// The name string needs leaves 0x8000'0002-0x8000'0004.
- if (io.template Read<CpuidMaximumExtendedLeaf>().reg_value() >= CpuidProcessorName4D::kLeaf) {
+ if (io.template Read<CpuidMaximumExtendedLeaf>().leaf() >= CpuidProcessorName4D::kLeaf) {
const uint32_t values[] = {
- io.template Read<CpuidProcessorName2A>().reg_value(),
- io.template Read<CpuidProcessorName2B>().reg_value(),
- io.template Read<CpuidProcessorName2C>().reg_value(),
- io.template Read<CpuidProcessorName2D>().reg_value(),
- io.template Read<CpuidProcessorName3A>().reg_value(),
- io.template Read<CpuidProcessorName3B>().reg_value(),
- io.template Read<CpuidProcessorName3C>().reg_value(),
- io.template Read<CpuidProcessorName3D>().reg_value(),
- io.template Read<CpuidProcessorName4A>().reg_value(),
- io.template Read<CpuidProcessorName4B>().reg_value(),
- io.template Read<CpuidProcessorName4C>().reg_value(),
- io.template Read<CpuidProcessorName4D>().reg_value(),
+ io.template Read<CpuidProcessorName2A>().value(),
+ io.template Read<CpuidProcessorName2B>().value(),
+ io.template Read<CpuidProcessorName2C>().value(),
+ io.template Read<CpuidProcessorName2D>().value(),
+ io.template Read<CpuidProcessorName3A>().value(),
+ io.template Read<CpuidProcessorName3B>().value(),
+ io.template Read<CpuidProcessorName3C>().value(),
+ io.template Read<CpuidProcessorName3D>().value(),
+ io.template Read<CpuidProcessorName4A>().value(),
+ io.template Read<CpuidProcessorName4B>().value(),
+ io.template Read<CpuidProcessorName4C>().value(),
+ io.template Read<CpuidProcessorName4D>().value(),
};
static_assert(kSize == sizeof(values));
memcpy(str_.data(), values, kSize);
diff --git a/zircon/kernel/lib/arch/test/cpuid-corpus-tests.cc b/zircon/kernel/lib/arch/test/cpuid-corpus-tests.cc
index 10ee96f..6f4d90b 100644
--- a/zircon/kernel/lib/arch/test/cpuid-corpus-tests.cc
+++ b/zircon/kernel/lib/arch/test/cpuid-corpus-tests.cc
@@ -546,7 +546,7 @@
auto hypervisor = arch::HypervisorName(cpuid);
EXPECT_TRUE(hypervisor.name() == "VBoxVBoxVBox"sv);
- EXPECT_EQ(0x4000'0006, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().reg_value());
+ EXPECT_EQ(0x4000'0006, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().leaf());
{
auto features = cpuid.Read<arch::CpuidFeatureFlagsC>();
@@ -596,7 +596,7 @@
auto hypervisor = arch::HypervisorName(cpuid);
EXPECT_TRUE(hypervisor.name() == "KVMKVMKVM"sv);
- EXPECT_EQ(0x4000'0001, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().reg_value());
+ EXPECT_EQ(0x4000'0001, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().leaf());
{
auto features = cpuid.Read<arch::CpuidFeatureFlagsC>();
@@ -646,7 +646,7 @@
auto hypervisor = arch::HypervisorName(cpuid);
EXPECT_TRUE(hypervisor.name() == "VMwareVMware"sv);
- EXPECT_EQ(0x4000'0010, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().reg_value());
+ EXPECT_EQ(0x4000'0010, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().leaf());
{
auto features = cpuid.Read<arch::CpuidFeatureFlagsC>();
@@ -694,7 +694,7 @@
auto hypervisor = arch::HypervisorName(cpuid);
EXPECT_TRUE(hypervisor.name() == "Microsoft Hv"sv);
- EXPECT_EQ(0x4000'000b, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().reg_value());
+ EXPECT_EQ(0x4000'000b, cpuid.Read<arch::CpuidMaximumHypervisorLeaf>().leaf());
{
auto features = cpuid.Read<arch::CpuidFeatureFlagsC>();
diff --git a/zircon/kernel/lib/arch/test/fake-cpuid-tests.cc b/zircon/kernel/lib/arch/test/fake-cpuid-tests.cc
index 946489b..e848a7b 100644
--- a/zircon/kernel/lib/arch/test/fake-cpuid-tests.cc
+++ b/zircon/kernel/lib/arch/test/fake-cpuid-tests.cc
@@ -59,7 +59,7 @@
// Read should be a shortcut to reading our the value type.
EXPECT_EQ(0x0000'0014, io->values_[arch::CpuidIo::kEax]);
- EXPECT_EQ(0x0000'0014, cpuid.Read<arch::CpuidMaximumLeaf>().reg_value());
+ EXPECT_EQ(0x0000'0014, cpuid.Read<arch::CpuidMaximumLeaf>().leaf());
}
TEST(FakeCpuidIoTests, PopulateOverwrites) {
diff --git a/zircon/kernel/lib/arch/testing/include/lib/arch/testing/x86/fake-cpuid.h b/zircon/kernel/lib/arch/testing/include/lib/arch/testing/x86/fake-cpuid.h
index c4a315f..a427656 100644
--- a/zircon/kernel/lib/arch/testing/include/lib/arch/testing/x86/fake-cpuid.h
+++ b/zircon/kernel/lib/arch/testing/include/lib/arch/testing/x86/fake-cpuid.h
@@ -17,25 +17,26 @@
// FakeCpuidIo is a fake analogue to arch::BootCpuidIo, which may be provided
// in its place for tests - in the kernel and on host - for logic templated
-// on any type the interface contract of the latter. Using `Populate`, test
-// authors can provide dummy data for specific (sub)leaves.
+// on any type the interface contract of the latter. A "CPUID I/O provider",
+// FakeCpuidIo's methods are expected to be instantiated by "CPUID value
+// types", defined in <lib/arch/x86/cpuid.h>.
+//
+// Using `Populate`, test authors can provide dummy data for specific
+// (sub)leaves.
//
// FakeCpuidIo is immovable and non-copyable; it is expected to be passed
// around by const reference.
class FakeCpuidIo {
public:
// Returns the cached CpuidIo object corresponding to the particular CPUID
- // register type. This method mirrors that of arch::BootCpuidIo and is
- // required to meet its interface contract.
+ // register type.
template <typename CpuidValue>
const CpuidIo* Get() const {
return Get(CpuidValue::kLeaf, CpuidValue::kSubleaf);
}
// A convenience method to directly read a particular CPUID register type in
- // consultation with the associated cached CpuidIo objects. This method
- // mirrors that of arch::BootCpuidIo and is required to meet its interface
- // contract.
+ // consultation with the associated cached CpuidIo objects.
template <typename CpuidValue>
auto Read() const {
return CpuidValue::Get().ReadFrom(Get<CpuidValue>());
diff --git a/zircon/kernel/lib/arch/x86/include/lib/arch/x86/boot-cpuid.h b/zircon/kernel/lib/arch/x86/include/lib/arch/x86/boot-cpuid.h
index 6ae43c0..3e1fe4a 100644
--- a/zircon/kernel/lib/arch/x86/include/lib/arch/x86/boot-cpuid.h
+++ b/zircon/kernel/lib/arch/x86/include/lib/arch/x86/boot-cpuid.h
@@ -54,14 +54,32 @@
} // namespace internal
-// This can be instantiated for any type <lib/arch/x86/cpuid.h> defines.
+// A "CPUID I/O provider", BootCpuidIo's methods are expected to be
+// instantiated by "CPUID value types", defined in <lib/arch/x86/cpuid.h>.
+//
// `BootCpuidIo<T>{}.Get()` returns a `const arch::CpuidIo*` that can be used
-// with the `hwreg` objects from `T::Get()`. InitializeBootCpuid() fills in
+// with the `hwreg` objects from `T::Get()`. InitializeBootCpuid() fills in
// the data for all the instantiations linked in.
//
// This template can be used as a parameter for template functions, e.g.
// `arch::GetVendor(BootCpuidIo{})`.
-struct BootCpuidIo {
+class BootCpuidIo {
+ public:
+ // Most often just Get<Type> is used instead to reach a particular (sub)leaf.
+ // Multiple different CpuidValue types reach the same (sub)leaf, usually one
+ // type for each of the four registers.
+ template <typename CpuidValue>
+ const CpuidIo* Get() const {
+ return GetLeaf<CpuidValue::kLeaf, CpuidValue::kSubleaf>();
+ }
+
+ // Convenience accessor for the common case.
+ template <typename CpuidValue>
+ auto Read() const {
+ return CpuidValue::Get().ReadFrom(Get<CpuidValue>());
+ }
+
+ private:
// The underlying instantiation is indexed by leaf and subleaf.
template <uint32_t Leaf, uint32_t Subleaf = 0>
const CpuidIo* GetLeaf() const {
@@ -101,20 +119,6 @@
#endif // __clang__
return &gCpuidIo;
}
-
- // Most often just Get<Type> is used instead to reach a particular (sub)leaf.
- // Multiple different CpuidValue types reach the same (sub)leaf, usually one
- // type for each of the four registers.
- template <typename CpuidValue>
- const CpuidIo* Get() const {
- return GetLeaf<CpuidValue::kLeaf, CpuidValue::kSubleaf>();
- }
-
- // Convenience accessor for the common case.
- template <typename CpuidValue>
- auto Read() const {
- return CpuidValue::Get().ReadFrom(Get<CpuidValue>());
- }
};
// Call this once early in startup, before any uses of arch::BootCpuIdIo. It
diff --git a/zircon/system/ulib/fidl/BUILD.zircon.gn b/zircon/system/ulib/fidl/BUILD.zircon.gn
index 727a9e1..43b9460 100644
--- a/zircon/system/ulib/fidl/BUILD.zircon.gn
+++ b/zircon/system/ulib/fidl/BUILD.zircon.gn
@@ -139,6 +139,9 @@
# <lib/fidl/llcpp/traits.h> has #include <lib/zx/object.h>.
"$zx/system/ulib/zx:headers",
+
+ # <lib/fidl/llcpp/connect_service.h> has #include <lib/zx/status.h>.
+ "$zx/system/ulib/zxc:headers",
]
deps = [
":fidl",
@@ -147,6 +150,7 @@
"$zx/system/ulib/fit",
"$zx/system/ulib/sync",
"$zx/system/ulib/zircon",
+ "$zx/system/ulib/zxc",
]
}
} else {
@@ -175,12 +179,16 @@
"llcpp_coding.c",
"llcpp_message.cc",
]
- public_deps = [ "$zx/system/ulib/zircon:headers" ]
+ public_deps = [
+ "$zx/system/ulib/zircon:headers",
+ "$zx/system/ulib/zxc:headers",
+ ]
deps = [
":fidl_base",
"$zx/system/ulib/fbl",
"$zx/system/ulib/fit",
"$zx/system/ulib/zircon",
+ "$zx/system/ulib/zxc",
]
}
}
diff --git a/zircon/system/ulib/fidl/include/lib/fidl/llcpp/connect_service.h b/zircon/system/ulib/fidl/include/lib/fidl/llcpp/connect_service.h
index dcc8697..daafb46 100644
--- a/zircon/system/ulib/fidl/include/lib/fidl/llcpp/connect_service.h
+++ b/zircon/system/ulib/fidl/include/lib/fidl/llcpp/connect_service.h
@@ -5,12 +5,15 @@
#ifndef LIB_FIDL_LLCPP_CONNECT_SERVICE_H_
#define LIB_FIDL_LLCPP_CONNECT_SERVICE_H_
+#include <lib/fidl/llcpp/client_end.h>
+#include <lib/fidl/llcpp/server_end.h>
#include <lib/fidl/llcpp/string_view.h>
#include <lib/fit/result.h>
#include <zircon/fidl.h>
#ifdef __Fuchsia__
#include <lib/zx/channel.h>
+#include <lib/zx/status.h>
#endif // __Fuchsia__
namespace fidl {
@@ -22,6 +25,7 @@
#ifdef __Fuchsia__
+// TODO(fxbug.dev/65212): ClientChannel may be replaced by fidl::ClientEnd.
// A wrapper around a Zircon channel, strongly-typed on a FIDL protocol.
template <typename FidlProtocol>
class ClientChannel final {
@@ -46,6 +50,44 @@
return typename FidlProtocol::SyncClient(channel.take_channel());
}
+template <typename Protocol>
+struct Endpoints {
+ fidl::ClientEnd<Protocol> client;
+ fidl::ServerEnd<Protocol> server;
+};
+
+// Creates a pair of Zircon channel endpoints speaking the |Protocol| protocol.
+// Whenever interacting with LLCPP, using this method should be encouraged over
+// |zx::channel::create|, because this method encodes the precise protocol type
+// into its results at compile time.
+//
+// The return value is a result type wrapping the client and server endpoints.
+// Given the following:
+//
+// auto endpoints = fidl::CreateEndpoints<MyProtocol>();
+//
+// The caller should first ensure that |endpoints.is_ok() == true|, after which
+// the channel endpoints may be accessed in one of two ways:
+//
+// - Direct:
+// endpoints->client;
+// endpoints->server;
+//
+// - Structured Binding:
+// auto [client_end, server_end] = std::move(endpoints.value());
+template <typename Protocol>
+zx::status<Endpoints<Protocol>> CreateEndpoints() {
+ zx::channel local, remote;
+ zx_status_t status = zx::channel::create(0, &local, &remote);
+ if (status != ZX_OK) {
+ return zx::error_status(status);
+ }
+ return zx::ok(Endpoints<Protocol>{
+ fidl::ClientEnd<Protocol>(std::move(local)),
+ fidl::ServerEnd<Protocol>(std::move(remote)),
+ });
+}
+
namespace internal {
// The method signature required to implement the method that issues the Directory::Open
diff --git a/zircon/system/ulib/zbitl/include/lib/zbitl/items/mem_config.h b/zircon/system/ulib/zbitl/include/lib/zbitl/items/mem_config.h
index 6b6c23a..0977364 100644
--- a/zircon/system/ulib/zbitl/include/lib/zbitl/items/mem_config.h
+++ b/zircon/system/ulib/zbitl/include/lib/zbitl/items/mem_config.h
@@ -109,6 +109,103 @@
View<ByteView> view_;
};
+// Takes an iterator yielding a sorted list of zbi_mem_range_t items, and merges
+// together contiguous ranges of the same type.
+template <typename Iterator>
+class MemRangeMerger {
+ public:
+ MemRangeMerger() = default;
+ MemRangeMerger(Iterator begin, Iterator end) : begin_(begin), end_(end) {}
+
+ class iterator;
+ iterator begin() const { return iterator(begin_, end_); }
+ iterator end() const { return iterator(end_, end_); }
+
+ class iterator {
+ public:
+ iterator(Iterator begin, Iterator end) : it_(begin), next_(begin), end_(end) { Next(); }
+
+ // Iterator traits.
+ using iterator_category = std::input_iterator_tag;
+ using reference = const zbi_mem_range_t&;
+ using value_type = zbi_mem_range_t;
+ using pointer = const zbi_mem_range_t*;
+ using difference_type = size_t;
+
+ // Equality / inequality.
+ bool operator==(const iterator& other) const { return it_ == other.it_; }
+ bool operator!=(const iterator& other) const { return !(*this == other); }
+
+ // Return the current element.
+ const zbi_mem_range_t& operator*() const {
+ ZX_DEBUG_ASSERT_MSG(it_ != end_, "Attempted to dereference 'end' iterator.");
+ return current_;
+ }
+ const zbi_mem_range_t* operator->() {
+ ZX_DEBUG_ASSERT_MSG(it_ != end_, "Attempted to dereference 'end' iterator.");
+ return ¤t_;
+ }
+
+ // Increment operators: move iterator to next element.
+ iterator& operator++() { // prefix
+ Next();
+ return *this;
+ }
+ iterator operator++(int) { // postfix
+ iterator result = *this;
+ ++this;
+ return result;
+ }
+
+ private:
+ // Ensure iterator type is valid.
+ static_assert(std::is_same_v<zbi_mem_range_t, typename Iterator::value_type>,
+ "Expected an iterator of type zbi_mem_range_t.");
+
+ // Fill `current_` with the next merged range.
+ void Next() {
+ // If we are at the end, do nothing.
+ it_ = next_;
+ if (it_ == end_) {
+ return;
+ }
+
+ // Keep merging entries together until we hit the end of our input
+ // or hit a discontinuity.
+ current_ = *next_;
+ ++next_;
+ while (next_ != end_) {
+ zbi_mem_range_t next = *next_;
+ // Ensure the end of this region is the start of the next.
+ if (current_.paddr + current_.length != next.paddr) {
+ break;
+ }
+ // Ensure the type of this region matches the next.
+ if (current_.type != next.type) {
+ break;
+ }
+ // Increase the size of this region.
+ current_.length += next.length;
+ ++next_;
+ }
+ }
+
+ // The merged memory range.
+ zbi_mem_range_t current_;
+
+ // The pair [it_, next_) represent the range of items merged into current_.
+ Iterator it_;
+ Iterator next_;
+
+ // The end_ iterator of the underlying container.
+ Iterator end_;
+ };
+
+ private:
+ Iterator begin_;
+ Iterator end_;
+};
+
} // namespace zbitl
#endif // LIB_ZBITL_ITEMS_MEM_CONFIG_H_
diff --git a/zircon/system/ulib/zbitl/test/mem_config_test.cc b/zircon/system/ulib/zbitl/test/mem_config_test.cc
index d78a191..79e96f2 100644
--- a/zircon/system/ulib/zbitl/test/mem_config_test.cc
+++ b/zircon/system/ulib/zbitl/test/mem_config_test.cc
@@ -528,4 +528,124 @@
ranges.back()));
}
+TEST(MemRangeMerger, Empty) {
+ std::vector<zbi_mem_range_t> input{};
+ zbitl::MemRangeMerger merger(input.begin(), input.end());
+ EXPECT_EQ(merger.begin(), merger.end());
+}
+
+TEST(MemRangeMerger, SingleItem) {
+ // Create an input with just a single range.
+ std::vector<zbi_mem_range_t> input = {
+ zbi_mem_range_t{
+ .paddr = 1,
+ .length = 2,
+ .type = 3,
+ },
+ };
+ zbitl::MemRangeMerger merger(input.begin(), input.end());
+ EXPECT_NE(merger.begin(), merger.end());
+
+ // Check first element.
+ auto it = merger.begin();
+ EXPECT_EQ(it->paddr, 1u);
+ EXPECT_EQ(it->length, 2u);
+ EXPECT_EQ(it->type, 3u);
+
+ // Should be no more elements.
+ ++it;
+ EXPECT_EQ(it, merger.end());
+}
+
+TEST(MemRangeMerger, MergeItems) {
+ // Create an input with multiple ranges to be merged.
+ std::vector<zbi_mem_range_t> input = {
+ zbi_mem_range_t{
+ .paddr = 0,
+ .length = 100,
+ .type = 1,
+ },
+ zbi_mem_range_t{
+ .paddr = 100,
+ .length = 200,
+ .type = 1,
+ },
+ zbi_mem_range_t{
+ .paddr = 300,
+ .length = 100,
+ .type = 1,
+ },
+ };
+ zbitl::MemRangeMerger merger(input.begin(), input.end());
+
+ // Merge the items.
+ std::vector<zbi_mem_range_t> result(merger.begin(), merger.end());
+
+ // Ensure we got the correctly merged results.
+ ASSERT_EQ(result.size(), 1u);
+ EXPECT_EQ(result[0].paddr, 0u);
+ EXPECT_EQ(result[0].length, 400u);
+ EXPECT_EQ(result[0].type, 1u);
+}
+
+TEST(MemRangeMerger, ShouldNotCombineNonContiguousItems) {
+ // Ensure we don't merge non-contiguous items.
+ std::vector<zbi_mem_range_t> input = {
+ zbi_mem_range_t{
+ .paddr = 0,
+ .length = 1,
+ .type = 1,
+ },
+ zbi_mem_range_t{
+ .paddr = 2, // skips byte 1; should not be merged.
+ .length = 1,
+ .type = 1,
+ },
+ zbi_mem_range_t{
+ .paddr = 3, // not the same type; should not be merged.
+ .length = 1,
+ .type = 2,
+ },
+ };
+ zbitl::MemRangeMerger merger(input.begin(), input.end());
+
+ // Merge the items.
+ std::vector<zbi_mem_range_t> result(merger.begin(), merger.end());
+
+ // Ensure the input matches the output.
+ ASSERT_EQ(result.size(), input.size());
+ for (size_t i = 0; i < input.size(); i++) {
+ EXPECT_EQ(input[i].paddr, result[i].paddr);
+ EXPECT_EQ(input[i].length, result[i].length);
+ EXPECT_EQ(input[i].type, result[i].type);
+ }
+}
+
+TEST(MemRangeMerger, MemRangeTableIterator) {
+ // Create a MemRangeTable, and use it as our input.
+ ZbiMemoryImage zbi = CreateImage();
+ AppendPayload(zbi, ZBI_TYPE_EFI_MEMORY_MAP,
+ JoinBytes(uint64_t{sizeof(efi_memory_descriptor)},
+ efi_memory_descriptor{
+ .Type = 1,
+ .PhysicalStart = 0x1000,
+ .NumberOfPages = 1,
+ },
+ efi_memory_descriptor{
+ .Type = 1,
+ .PhysicalStart = 0x2000,
+ .NumberOfPages = 2,
+ }));
+
+ // Merge elements together.
+ zbitl::MemRangeTable container{AsView(zbi)};
+ zbitl::MemRangeMerger merger(container.begin(), container.end());
+ std::vector<zbi_mem_range_t> ranges(merger.begin(), merger.end());
+ ASSERT_TRUE(container.take_error().is_ok());
+ ASSERT_EQ(ranges.size(), 1u);
+ EXPECT_EQ(ranges[0].paddr, 0x1000u);
+ EXPECT_EQ(ranges[0].length, 0x3000u);
+ EXPECT_EQ(ranges[0].type, 1u);
+}
+
} // namespace