Snap for 11224086 from bb30fa3297cbd71e0086d20a1740359641def129 to mainline-tzdata5-release

Change-Id: I1c260eaf65f51a438967bf15ec800d3a1ae5ec4d
diff --git a/TEST_MAPPING b/TEST_MAPPING
index f711b63..fadf79d 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -28,6 +28,15 @@
     },
     {
       "name": "CtsScopedStorageDeviceOnlyTest"
+    },
+    {
+      "name": "CtsScopedStorageBypassDatabaseOperationsTest"
+    },
+    {
+      "name": "CtsScopedStorageGeneralTest"
+    },
+    {
+      "name": "CtsScopedStorageRedactUriTest"
     }
   ],
   "auto-presubmit": [
diff --git a/common/libs/security/Android.bp b/common/libs/security/Android.bp
index 758b8bf..dcc5b70 100644
--- a/common/libs/security/Android.bp
+++ b/common/libs/security/Android.bp
@@ -21,6 +21,7 @@
     name: "libcuttlefish_security",
     defaults: ["hidl_defaults", "cuttlefish_host"],
     srcs: [
+        "channel.cpp",
         "gatekeeper_channel.cpp",
         "keymaster_channel.cpp",
     ],
@@ -39,6 +40,7 @@
                 "libcuttlefish_fs",
             ],
             srcs: [
+                "channel_sharedfd.cpp",
                 "confui_sign.cpp",
                 "gatekeeper_channel_sharedfd.cpp",
                 "keymaster_channel_sharedfd.cpp",
diff --git a/common/libs/security/channel.cpp b/common/libs/security/channel.cpp
new file mode 100644
index 0000000..e2891aa
--- /dev/null
+++ b/common/libs/security/channel.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "common/libs/security/channel.h"
+
+#include "keymaster/android_keymaster_utils.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+void MessageDestroyer::operator()(RawMessage* ptr) {
+  {
+    keymaster::Eraser(ptr, sizeof(RawMessage) + ptr->payload_size);
+  }
+  std::free(ptr);
+}
+
+/**
+ * Allocates memory for a RawMessage carrying a message of size
+ * `payload_size`.
+ */
+Result<ManagedMessage> CreateMessage(uint32_t command, bool is_response, size_t payload_size) {
+  const auto bytes_to_allocate = sizeof(RawMessage) + payload_size;
+  auto memory = std::malloc(bytes_to_allocate);
+  CF_EXPECT(memory != nullptr,
+            "Cannot allocate " << bytes_to_allocate << " bytes for secure_env RPC message");
+  auto message = reinterpret_cast<RawMessage*>(memory);
+  message->command = command;
+  message->is_response = is_response;
+  message->payload_size = payload_size;
+  return ManagedMessage(message);
+}
+
+Result<ManagedMessage> CreateMessage(uint32_t command, size_t payload_size) {
+  return CreateMessage(command, false, payload_size);
+}
+
+}  // namespace secure_env
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/security/channel.h b/common/libs/security/channel.h
new file mode 100644
index 0000000..eb415e2
--- /dev/null
+++ b/common/libs/security/channel.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "common/libs/utils/result.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+/**
+ * RawMessage - Header and raw byte payload for a serialized
+ * secure env message.
+ *
+ * @command: the command.
+ * @is_response: flag to mark message as a request/response.
+ * @payload_size: amount of payload data we're going to transfer.
+ * @payload: start of the serialized command specific payload.
+ */
+struct RawMessage {
+  uint32_t command : 31;
+  bool is_response : 1;
+  uint32_t payload_size;
+  uint8_t payload[0];
+};
+
+/**
+ * A destroyer for RawMessage instances created with
+ * CreateMessage. Wipes memory from the RawMessage
+ * instances.
+ */
+class MessageDestroyer {
+ public:
+  void operator()(RawMessage* ptr);
+};
+
+/** An owning pointer for a RawMessage instance. */
+using ManagedMessage = std::unique_ptr<RawMessage, MessageDestroyer>;
+
+/**
+ * Allocates memory for a RawMessage carrying a message of size
+ * `payload_size`.
+ */
+Result<ManagedMessage> CreateMessage(uint32_t command, bool is_response, size_t payload_size);
+Result<ManagedMessage> CreateMessage(uint32_t command, size_t payload_size);
+
+/*
+ * Interface for communication channels that synchronously communicate
+ * HAL IPC/RPC calls.
+ */
+class Channel {
+ public:
+  virtual Result<void> SendRequest(RawMessage& message) = 0;
+  virtual Result<void> SendResponse(RawMessage& message) = 0;
+  virtual Result<ManagedMessage> ReceiveMessage() = 0;
+  virtual ~Channel() {}
+};
+
+}  // namespace secure_env
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/security/channel_sharedfd.cpp b/common/libs/security/channel_sharedfd.cpp
new file mode 100644
index 0000000..a152cf3
--- /dev/null
+++ b/common/libs/security/channel_sharedfd.cpp
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "common/libs/security/channel_sharedfd.h"
+
+#include "common/libs/fs/shared_buf.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+SharedFdChannel::SharedFdChannel(SharedFD input, SharedFD output)
+    : input_(std::move(input)), output_(std::move(output)) {}
+
+Result<void> SharedFdChannel::SendRequest(RawMessage& message) {
+  return SendMessage(message, false);
+}
+
+Result<void> SharedFdChannel::SendResponse(RawMessage& message) {
+  return SendMessage(message, true);
+}
+
+Result<ManagedMessage> SharedFdChannel::ReceiveMessage() {
+  struct RawMessage message_header;
+  auto read = ReadExactBinary(input_, &message_header);
+  CF_EXPECT(read == sizeof(RawMessage),
+            "Expected " << sizeof(RawMessage) << ", received " << read << "\n" <<
+            "Could not read message: " << input_->StrError());
+  LOG(DEBUG) << "Received message with id: " << message_header.command;
+
+  auto message = CF_EXPECT(CreateMessage(message_header.command, message_header.is_response,
+                                         message_header.payload_size));
+  auto message_bytes = reinterpret_cast<char*>(message->payload);
+  read = ReadExact(input_, message_bytes, message->payload_size);
+  CF_EXPECT(read == message->payload_size,
+            "Could not read message: " << input_->StrError());
+
+  return message;
+}
+
+Result<void> SharedFdChannel::SendMessage(RawMessage& message, bool response) {
+  message.is_response = response;
+  auto write_size = sizeof(RawMessage) + message.payload_size;
+  auto message_bytes = reinterpret_cast<const char*>(&message);
+  auto written = WriteAll(output_, message_bytes, write_size);
+  CF_EXPECT(written == write_size,
+            "Could not write message: " << output_->StrError());
+  return {};
+}
+
+}  // namespace secure_env
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/security/channel_sharedfd.h b/common/libs/security/channel_sharedfd.h
new file mode 100644
index 0000000..39f2749
--- /dev/null
+++ b/common/libs/security/channel_sharedfd.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/channel.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+class SharedFdChannel : public Channel {
+ public:
+  SharedFdChannel(SharedFD input, SharedFD output);
+  Result<void> SendRequest(RawMessage& message) override;
+  Result<void> SendResponse(RawMessage& message) override;
+  Result<ManagedMessage> ReceiveMessage() override;
+
+ private:
+  SharedFD input_;
+  SharedFD output_;
+
+  Result<void> SendMessage(RawMessage& message, bool response);
+};
+
+}  // namespace secure_env
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/common/libs/security/oemlock.h b/common/libs/security/oemlock.h
new file mode 100644
index 0000000..d5fb62d
--- /dev/null
+++ b/common/libs/security/oemlock.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+namespace cuttlefish {
+namespace secure_env {
+
+enum class OemLockField : uint32_t {
+  ALLOWED_BY_CARRIER = 0,
+  ALLOWED_BY_DEVICE,
+  ALLOWED,
+  LOCKED,
+};
+
+}  // namespace secure_env
+}  // namespace cuttlefish
\ No newline at end of file
diff --git a/guest/hals/keymint/rust/src/keymint_hal_main.rs b/guest/hals/keymint/rust/src/keymint_hal_main.rs
index 08709b7..ff4df21 100644
--- a/guest/hals/keymint/rust/src/keymint_hal_main.rs
+++ b/guest/hals/keymint/rust/src/keymint_hal_main.rs
@@ -23,7 +23,7 @@
 use std::sync::{Arc, Mutex};
 
 /// Device file used to communicate with the KeyMint TA.
-static DEVICE_FILE_NAME: &str = "/dev/hvc3";
+static DEVICE_FILE_NAME: &str = "/dev/hvc11";
 
 /// Name of KeyMint binder device instance.
 static SERVICE_INSTANCE: &str = "default";
diff --git a/guest/hals/oemlock/remote/Android.bp b/guest/hals/oemlock/remote/Android.bp
new file mode 100644
index 0000000..6c2f3b9
--- /dev/null
+++ b/guest/hals/oemlock/remote/Android.bp
@@ -0,0 +1,42 @@
+//
+// Copyright (C) 2023 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.
+//
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+    name: "android.hardware.oemlock-service.remote",
+    defaults: ["cuttlefish_guest_only"],
+    vendor: true,
+    relative_install_path: "hw",
+    init_rc: ["android.hardware.oemlock-service.remote.rc"],
+
+    srcs: [
+        "remote_oemlock.cpp",
+        "service.cpp",
+    ],
+
+    shared_libs: [
+        "android.hardware.oemlock-V1-ndk",
+        "libbase",
+        "libbinder_ndk",
+        "libcuttlefish_fs",
+        "libcuttlefish_security",
+    ],
+
+    vintf_fragments: ["android.hardware.oemlock-service.remote.xml"],
+}
diff --git a/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.rc b/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.rc
new file mode 100644
index 0000000..15963aa
--- /dev/null
+++ b/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.rc
@@ -0,0 +1,4 @@
+service vendor.oemlock_default /vendor/bin/hw/android.hardware.oemlock-service.remote /dev/hvc10
+    class hal
+    user hsm
+    group hsm
diff --git a/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.xml b/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.xml
new file mode 100644
index 0000000..d5905d8
--- /dev/null
+++ b/guest/hals/oemlock/remote/android.hardware.oemlock-service.remote.xml
@@ -0,0 +1,10 @@
+<manifest version="1.0" type="device">
+    <hal format="aidl">
+        <name>android.hardware.oemlock</name>
+        <version>1</version>
+        <interface>
+            <name>IOemLock</name>
+            <instance>default</instance>
+        </interface>
+    </hal>
+</manifest>
diff --git a/guest/hals/oemlock/remote/remote_oemlock.cpp b/guest/hals/oemlock/remote/remote_oemlock.cpp
new file mode 100644
index 0000000..46727be
--- /dev/null
+++ b/guest/hals/oemlock/remote/remote_oemlock.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include "guest/hals/oemlock/remote/remote_oemlock.h"
+
+#include <android-base/logging.h>
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace oemlock {
+namespace {
+
+enum {
+    CUSTOM_ERROR_TRANSPORT_IS_FAILED = 0,
+};
+
+::ndk::ScopedAStatus resultToStatus(Result<void> r) {
+    if (r.ok())
+        return ::ndk::ScopedAStatus::ok();
+    else
+        return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+                CUSTOM_ERROR_TRANSPORT_IS_FAILED, r.error().Message().c_str());
+}
+
+}
+
+OemLock::OemLock(secure_env::Channel& channel) : channel_(channel) {}
+
+::ndk::ScopedAStatus OemLock::getName(std::string *out_name) {
+    *out_name = "CF Remote Implementation";
+    return ::ndk::ScopedAStatus::ok();
+}
+
+::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByCarrier(bool in_allowed,
+                                                           const std::vector<uint8_t> &,
+                                                           OemLockSecureStatus *_aidl_return) {
+    *_aidl_return = OemLockSecureStatus::OK;
+    return resultToStatus(setValue(secure_env::OemLockField::ALLOWED_BY_CARRIER, in_allowed));
+}
+
+::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByCarrier(bool *out_allowed) {
+    return resultToStatus(requestValue(secure_env::OemLockField::ALLOWED_BY_CARRIER, out_allowed));
+}
+
+::ndk::ScopedAStatus OemLock::setOemUnlockAllowedByDevice(bool in_allowed) {
+    return resultToStatus(setValue(secure_env::OemLockField::ALLOWED_BY_DEVICE, in_allowed));
+}
+
+::ndk::ScopedAStatus OemLock::isOemUnlockAllowedByDevice(bool *out_allowed) {
+    return resultToStatus(requestValue(secure_env::OemLockField::ALLOWED_BY_DEVICE, out_allowed));
+}
+
+Result<void> OemLock::requestValue(secure_env::OemLockField field, bool *out) {
+    auto message = CF_EXPECT(secure_env::CreateMessage(static_cast<uint32_t>(field), 0),
+                             "Cannot allocate message for oemlock request: " <<
+                             static_cast<uint32_t>(field));
+    CF_EXPECT(channel_.SendRequest(*message),
+              "Can't send get value request for field: " << static_cast<uint32_t>(field));
+    auto response = CF_EXPECT(channel_.ReceiveMessage(),
+                              "Haven't received an answer for getting the field: " <<
+                              static_cast<uint32_t>(field));
+    *out = *reinterpret_cast<bool*>(response->payload);
+    return {};
+}
+
+Result<void> OemLock::setValue(secure_env::OemLockField field, bool value) {
+    auto message = CF_EXPECT(secure_env::CreateMessage(static_cast<uint32_t>(field), sizeof(bool)),
+                             "Cannot allocate message for oemlock request: " <<
+                             static_cast<uint32_t>(field));
+    memcpy(message->payload, &value, sizeof(bool));
+    CF_EXPECT(channel_.SendRequest(*message),
+              "Can't send set value request for field: " << static_cast<uint32_t>(field));
+    auto response = CF_EXPECT(channel_.ReceiveMessage(),
+                              "Haven't received an answer for setting the field: " <<
+                              static_cast<uint32_t>(field));
+    auto updated_value = *reinterpret_cast<bool*>(response->payload);
+    CF_EXPECT(value == updated_value,
+              "Updated value for the field " << static_cast<uint32_t>(field) <<
+              " is different from what we wated to set");
+    return {};
+}
+
+} // namespace oemlock
+} // namespace hardware
+} // namespace android
+} // aidl
diff --git a/guest/hals/oemlock/remote/remote_oemlock.h b/guest/hals/oemlock/remote/remote_oemlock.h
new file mode 100644
index 0000000..c2aa5cb
--- /dev/null
+++ b/guest/hals/oemlock/remote/remote_oemlock.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/oemlock/BnOemLock.h>
+
+#include "common/libs/security/channel.h"
+#include "common/libs/security/oemlock.h"
+#include "common/libs/utils/result.h"
+
+namespace aidl {
+namespace android {
+namespace hardware {
+namespace oemlock {
+
+using namespace cuttlefish;
+
+struct OemLock : public BnOemLock {
+public:
+    OemLock(secure_env::Channel& channel);
+
+    // Methods from ::android::hardware::oemlock::IOemLock follow.
+    ::ndk::ScopedAStatus getName(std::string* out_name) override;
+    ::ndk::ScopedAStatus isOemUnlockAllowedByCarrier(bool* out_allowed) override;
+    ::ndk::ScopedAStatus isOemUnlockAllowedByDevice(bool* out_allowed) override;
+    ::ndk::ScopedAStatus setOemUnlockAllowedByCarrier(bool in_allowed,
+                                                      const std::vector<uint8_t>&,
+                                                      OemLockSecureStatus* _aidl_return) override;
+    ::ndk::ScopedAStatus setOemUnlockAllowedByDevice(bool in_allowed) override;
+
+private:
+    secure_env::Channel& channel_;
+
+    Result<void> requestValue(secure_env::OemLockField field, bool *out);
+    Result<void> setValue(secure_env::OemLockField field, bool value);
+};
+
+} // namespace oemlock
+} // namespace hardware
+} // namespace android
+} // aidl
diff --git a/guest/hals/oemlock/remote/service.cpp b/guest/hals/oemlock/remote/service.cpp
new file mode 100644
index 0000000..d1eefef
--- /dev/null
+++ b/guest/hals/oemlock/remote/service.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2023 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.
+ */
+
+#include <android-base/logging.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/channel_sharedfd.h"
+#include "guest/hals/oemlock/remote/remote_oemlock.h"
+
+using ::aidl::android::hardware::oemlock::OemLock;
+
+int main(int argc, char *argv[]) {
+    ::android::base::InitLogging(argv, ::android::base::KernelLogger);
+    ABinderProcess_setThreadPoolMaxThreadCount(0);
+
+    if (argc != 2) {
+        LOG(FATAL) << "Cuttlefish OemLock HAL requires to have hvc path as a first argument";
+    }
+    const auto fd = cuttlefish::SharedFD::Open(argv[1], O_RDWR);
+    if (!fd->IsOpen()) {
+        LOG(FATAL) << "Could not connect to oemlock: " << fd->StrError();
+    }
+    if (fd->SetTerminalRaw() < 0) {
+        LOG(FATAL) << "Could not make " << argv[1] << " a raw terminal: " << fd->StrError();
+    }
+
+    cuttlefish::secure_env::SharedFdChannel channel(fd, fd);
+    std::shared_ptr<OemLock> oemlock = ndk::SharedRefBase::make<OemLock>(channel);
+
+    const std::string instance = std::string() + OemLock::descriptor + "/default";
+    binder_status_t status = AServiceManager_addService(oemlock->asBinder().get(), instance.c_str());
+    CHECK_EQ(status, STATUS_OK);
+
+    ABinderProcess_joinThreadPool();
+    return -1; // Should never be reached
+}
diff --git a/guest/hals/ril/reference-ril/reference-ril.c b/guest/hals/ril/reference-ril/reference-ril.c
index 9fdf80d..762f1e4 100644
--- a/guest/hals/ril/reference-ril/reference-ril.c
+++ b/guest/hals/ril/reference-ril/reference-ril.c
@@ -845,8 +845,8 @@
          p_cur = p_cur->p_next)
         n++;
 
-    RIL_Data_Call_Response_v11 *responses =
-        alloca(n * sizeof(RIL_Data_Call_Response_v11));
+    RIL_Data_Call_Response_v11 *responses = (n == 0) ? NULL :
+                   alloca(n * sizeof(RIL_Data_Call_Response_v11));
 
     int i;
     for (i = 0; i < n; i++) {
@@ -996,7 +996,7 @@
     // If cid = -1, return the data call list without processing CGCONTRDP (setupDataCall)
     if (cid == -1) {
         if (t != NULL)
-            RIL_onRequestComplete(*t, RIL_E_SUCCESS, &responses[0],
+            RIL_onRequestComplete(*t, RIL_E_SUCCESS, responses,
                                   sizeof(RIL_Data_Call_Response_v11));
         else
             RIL_onUnsolicitedResponse(RIL_UNSOL_DATA_CALL_LIST_CHANGED, responses,
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index 9d285ec..266547a 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -254,6 +254,9 @@
       preserving.insert("persistent_composite.img");
       preserving.insert("uboot_env.img");
       preserving.insert("factory_reset_protected.img");
+      preserving.insert("misc.img");
+      preserving.insert("metadata.img");
+      preserving.insert("oemlock_insecure");
       std::stringstream ss;
       for (int i = 0; i < modem_simulator_count; i++) {
         ss.clear();
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index dc6e4f2..beae35e 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -901,8 +901,8 @@
  private:
   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
   Result<void> ResultSetup() override {
-    if (FileExists(instance_.metadata_image()) &&
-        FileSize(instance_.metadata_image()) == instance_.blank_metadata_image_mb() << 20) {
+    if (FileExists(instance_.new_metadata_image()) &&
+        FileSize(instance_.new_metadata_image()) == instance_.blank_metadata_image_mb() << 20) {
       return {};
     }
 
diff --git a/host/commands/cvd/Android.bp b/host/commands/cvd/Android.bp
index 6ec0535..a6d6ec4 100644
--- a/host/commands/cvd/Android.bp
+++ b/host/commands/cvd/Android.bp
@@ -141,24 +141,3 @@
     ],
     defaults: ["cvd_and_fetch_cvd_defaults"],
 }
-
-// These are set up as two separate executables rather than a symlink so that
-// either can be downloaded as a standalone statically linked executable from
-// the build system.
-
-cc_binary_host {
-    name: "cvd",
-    symlinks: ["acloud"],
-    static_libs: [
-        "cvd_and_fetch_cvd",
-    ],
-    defaults: ["cvd_and_fetch_cvd_defaults"],
-}
-
-cc_binary_host {
-    name: "fetch_cvd",
-    static_libs: [
-        "cvd_and_fetch_cvd",
-    ],
-    defaults: ["cvd_and_fetch_cvd_defaults"],
-}
diff --git a/host/commands/run_cvd/Android.bp b/host/commands/run_cvd/Android.bp
index 6f87114..335a51f 100644
--- a/host/commands/run_cvd/Android.bp
+++ b/host/commands/run_cvd/Android.bp
@@ -17,34 +17,6 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-// Allow the KeyMint reference implementation to be selected at build time.
-soong_config_module_type {
-    name: "keymint_impl_defaults",
-    module_type: "cc_defaults",
-    config_namespace: "secure_env",
-    variables: ["keymint_impl"],
-    properties: ["cflags"],
-}
-
-soong_config_string_variable {
-    name: "keymint_impl",
-    values: ["rust", "cpp"],
-}
-
-keymint_impl_defaults {
-    name: "secure_env_keymint_impl_defaults",
-    soong_config_variables: {
-        keymint_impl: {
-            rust: {
-                cflags: ["-DCUTTLEFISH_KEYMINT_RUST",],
-            },
-            cpp: {},
-            conditions_default: {},
-        },
-    },
-}
-
-
 cc_binary {
     name: "run_cvd",
     srcs: [
@@ -100,6 +72,5 @@
         "cuttlefish_host",
         "cuttlefish_libicuuc",
         "cvd_cc_defaults",
-        "secure_env_keymint_impl_defaults",
     ],
 }
diff --git a/host/commands/run_cvd/launch/secure_env.cpp b/host/commands/run_cvd/launch/secure_env.cpp
index b5e0cf8..a70fc14 100644
--- a/host/commands/run_cvd/launch/secure_env.cpp
+++ b/host/commands/run_cvd/launch/secure_env.cpp
@@ -46,18 +46,22 @@
     command.AddParameter("-keymaster_fd_in=", fifos_[1]);
     command.AddParameter("-gatekeeper_fd_out=", fifos_[2]);
     command.AddParameter("-gatekeeper_fd_in=", fifos_[3]);
+    command.AddParameter("-oemlock_fd_out=", fifos_[4]);
+    command.AddParameter("-oemlock_fd_in=", fifos_[5]);
+    command.AddParameter("-keymint_fd_out=", fifos_[6]);
+    command.AddParameter("-keymint_fd_in=", fifos_[7]);
 
     const auto& secure_hals = config_.secure_hals();
     bool secure_keymint = secure_hals.count(SecureHal::Keymint) > 0;
-#ifdef CUTTLEFISH_KEYMINT_RUST
-    command.AddParameter("-keymint_impl=",
-                         secure_keymint ? "rust-tpm" : "rust-software");
-#else
     command.AddParameter("-keymint_impl=", secure_keymint ? "tpm" : "software");
-#endif
     bool secure_gatekeeper = secure_hals.count(SecureHal::Gatekeeper) > 0;
     auto gatekeeper_impl = secure_gatekeeper ? "tpm" : "software";
     command.AddParameter("-gatekeeper_impl=", gatekeeper_impl);
+
+    bool secure_oemlock = secure_hals.count(SecureHal::Oemlock) > 0;
+    auto oemlock_impl = secure_oemlock ? "tpm" : "software";
+    command.AddParameter("-oemlock_impl=", oemlock_impl);
+
     command.AddParameter("-kernel_events_fd=", kernel_log_pipe_);
 
     std::vector<MonitorCommand> commands;
@@ -79,6 +83,10 @@
         instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
         instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
         instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
     };
     std::vector<SharedFD> fifos;
     for (const auto& path : fifo_paths) {
diff --git a/host/commands/run_cvd/server_loop.cpp b/host/commands/run_cvd/server_loop.cpp
index 6347670..b716e33 100644
--- a/host/commands/run_cvd/server_loop.cpp
+++ b/host/commands/run_cvd/server_loop.cpp
@@ -211,8 +211,12 @@
         instance_.logcat_pipe_name(),
         instance_.PerInstanceInternalPath("keymaster_fifo_vm.in"),
         instance_.PerInstanceInternalPath("keymaster_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("keymint_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("keymint_fifo_vm.out"),
         instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.in"),
         instance_.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
+        instance_.PerInstanceInternalPath("oemlock_fifo_vm.in"),
+        instance_.PerInstanceInternalPath("oemlock_fifo_vm.out"),
         instance_.PerInstanceInternalPath("bt_fifo_vm.in"),
         instance_.PerInstanceInternalPath("bt_fifo_vm.out"),
         instance_.PerInstanceInternalPath("uwb_fifo_vm.in"),
diff --git a/host/commands/secure_env/Android.bp b/host/commands/secure_env/Android.bp
index 9472874..a18ab26 100644
--- a/host/commands/secure_env/Android.bp
+++ b/host/commands/secure_env/Android.bp
@@ -78,6 +78,7 @@
         "json_serializable.cpp",
         "keymaster_responder.cpp",
         "primary_key_builder.cpp",
+        "storage/storage.cpp",
         "tpm_attestation_record.cpp",
         "tpm_auth.cpp",
         "tpm_commands.cpp",
@@ -94,11 +95,18 @@
         "tpm_serialize.cpp",
 ]
 
+// Things blocking us to use oemlock on windows:
+// 1. Missing transport implementation
+// 2. Missing file utils
+// 3. Base64 isn't supported (need for software oemlock implementation)
 cc_library_host_static {
     name: "libsecure_env_linux",
     srcs: common_libsecure_srcs + [
         "confui_sign_server.cpp",
         "device_tpm.cpp",
+        "oemlock/oemlock.cpp",
+        "oemlock/oemlock_responder.cpp",
+        "storage/insecure_json_storage.cpp",
     ],
     defaults: ["cuttlefish_buildhost_only", "secure_env_defaults"],
 }
diff --git a/host/commands/secure_env/doc/linkage.dot b/host/commands/secure_env/doc/linkage.dot
index 069ff82..9c9378c 100644
--- a/host/commands/secure_env/doc/linkage.dot
+++ b/host/commands/secure_env/doc/linkage.dot
@@ -9,12 +9,14 @@
   subgraph fifos {
     rank = same;
 
-    host_keymint_in [color = "blue", label = "internal/keymaster_fifo_vm.in", shape = "rectangle"]
-    host_keymint_out [color = "blue", label = "internal/keymaster_fifo_vm.out", shape = "rectangle"]
+    host_keymaster_in [color = "blue", label = "internal/keymaster_fifo_vm.in", shape = "rectangle"]
+    host_keymaster_out [color = "blue", label = "internal/keymaster_fifo_vm.out", shape = "rectangle"]
     host_gatekeeper_in [color = "green", label = "internal/gatekeeper_fifo_vm.in", shape = "rectangle"]
     host_gatekeeper_out [color = "green", label = "internal/gatekeeper_fifo_vm.out", shape = "rectangle"]
     host_confirmationui_in [color = "red", label = "internal/confui_fifo_vm.in", shape = "rectangle"]
     host_confirmationui_out [color = "red", label = "internal/confui_fifo_vm.out", shape = "rectangle"]
+    host_keymint_in [color = "blue", label = "internal/keymint_fifo_vm.in", shape = "rectangle"]
+    host_keymint_out [color = "blue", label = "internal/keymint_fifo_vm.out", shape = "rectangle"]
   }
 
   subgraph cluster_android {
@@ -22,13 +24,19 @@
     u_boot [label = "u-boot"]
     confirmationui [color = "red", label = "ConfirmationUI HAL"]
     gatekeeper [color = "green", label = "Gatekeeper HAL"]
-    keymint [color = "blue", label = "Keymint HAL"]
+    subgraph cluster_keymint {
+      graph[style=dotted]
+      label = "One of:"
+      keymaster [color = "blue", label = "KeyMint (C++) HAL"]
+      keymint [color = "blue", label = "KeyMint (Rust) HAL"]
+    }
 
     subgraph consoles {
-      	rank = same;
+        rank = same;
         confirmationui_console [color = "red", label = "/dev/hvc8", shape = "rectangle"]
         gatekeeper_console [color = "green", label = "/dev/hvc4", shape = "rectangle"]
-        keymint_console [color = "blue", label = "/dev/hvc3", shape = "rectangle"]
+        keymaster_console [color = "blue", label = "/dev/hvc3", shape = "rectangle"]
+        keymint_console [color = "blue", label = "/dev/hvc11", shape = "rectangle"]
     }
   }
 
@@ -44,9 +52,13 @@
   secure_env -> host_gatekeeper_in -> vmm [color = "green"]
   vmm -> gatekeeper_console -> gatekeeper [color = "green", dir = "both"]
 
+  secure_env -> host_keymaster_out -> vmm [color = "blue", dir = "back"]
+  secure_env -> host_keymaster_in -> vmm [color = "blue"]
+  vmm -> keymaster_console -> keymaster [color = "blue", dir = "both"]
+  keymaster_console -> u_boot [color = "blue", dir = "both"]
+
   secure_env -> host_keymint_out -> vmm [color = "blue", dir = "back"]
   secure_env -> host_keymint_in -> vmm [color = "blue"]
   vmm -> keymint_console -> keymint [color = "blue", dir = "both"]
-  keymint_console -> u_boot [color = "blue", dir = "both"]
 
 }
diff --git a/host/commands/secure_env/doc/linkage.png b/host/commands/secure_env/doc/linkage.png
index 2549569..10fba9a 100644
--- a/host/commands/secure_env/doc/linkage.png
+++ b/host/commands/secure_env/doc/linkage.png
Binary files differ
diff --git a/host/commands/secure_env/doc/linkage.svg b/host/commands/secure_env/doc/linkage.svg
index 6bb643f..f0ab640 100644
--- a/host/commands/secure_env/doc/linkage.svg
+++ b/host/commands/secure_env/doc/linkage.svg
@@ -4,278 +4,345 @@
 <!-- Generated by graphviz version 2.43.0 (0)
  -->
 <!-- Title: %3 Pages: 1 -->
-<svg width="1180pt" height="423pt"
- viewBox="0.00 0.00 1179.50 423.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 419)">
+<svg width="1567pt" height="434pt"
+ viewBox="0.00 0.00 1566.50 434.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 430)">
 <title>%3</title>
-<polygon fill="white" stroke="transparent" points="-4,4 -4,-419 1175.5,-419 1175.5,4 -4,4"/>
+<polygon fill="white" stroke="transparent" points="-4,4 -4,-430 1562.5,-430 1562.5,4 -4,4"/>
 <g id="clust2" class="cluster">
 <title>cluster_android</title>
-<polygon fill="none" stroke="black" points="297.5,-8 297.5,-155 879.5,-155 879.5,-8 297.5,-8"/>
-<text text-anchor="middle" x="588.5" y="-139.8" font-family="Times,serif" font-size="14.00">Android VM</text>
+<polygon fill="none" stroke="black" points="319.5,-8 319.5,-166 1154.5,-166 1154.5,-8 319.5,-8"/>
+<text text-anchor="middle" x="737" y="-150.8" font-family="Times,serif" font-size="14.00">Android VM</text>
+</g>
+<g id="clust3" class="cluster">
+<title>cluster_keymint</title>
+<polygon fill="none" stroke="black" stroke-dasharray="1,5" points="327.5,-16 327.5,-91 713.5,-91 713.5,-16 327.5,-16"/>
+<text text-anchor="middle" x="520.5" y="-75.8" font-family="Times,serif" font-size="14.00">One of:</text>
 </g>
 <!-- browser -->
 <g id="node1" class="node">
 <title>browser</title>
-<ellipse fill="none" stroke="black" cx="904.5" cy="-397" rx="40.09" ry="18"/>
-<text text-anchor="middle" x="904.5" y="-393.3" font-family="Times,serif" font-size="14.00">Browser</text>
+<ellipse fill="none" stroke="black" cx="1291.5" cy="-408" rx="40.09" ry="18"/>
+<text text-anchor="middle" x="1291.5" y="-404.3" font-family="Times,serif" font-size="14.00">Browser</text>
 </g>
 <!-- webRTC -->
 <g id="node6" class="node">
 <title>webRTC</title>
-<ellipse fill="none" stroke="black" cx="904.5" cy="-325" rx="42.49" ry="18"/>
-<text text-anchor="middle" x="904.5" y="-321.3" font-family="Times,serif" font-size="14.00">webRTC</text>
+<ellipse fill="none" stroke="black" cx="1291.5" cy="-336" rx="42.49" ry="18"/>
+<text text-anchor="middle" x="1291.5" y="-332.3" font-family="Times,serif" font-size="14.00">webRTC</text>
 </g>
 <!-- browser&#45;&gt;webRTC -->
 <g id="edge1" class="edge">
 <title>browser&#45;&gt;webRTC</title>
-<path fill="none" stroke="black" d="M904.5,-378.7C904.5,-370.98 904.5,-361.71 904.5,-353.11"/>
-<polygon fill="black" stroke="black" points="908,-353.1 904.5,-343.1 901,-353.1 908,-353.1"/>
+<path fill="none" stroke="black" d="M1291.5,-389.7C1291.5,-381.98 1291.5,-372.71 1291.5,-364.11"/>
+<polygon fill="black" stroke="black" points="1295,-364.1 1291.5,-354.1 1288,-364.1 1295,-364.1"/>
 </g>
 <!-- confirmationui_sign -->
 <g id="node2" class="node">
 <title>confirmationui_sign</title>
-<polygon fill="none" stroke="red" points="788.5,-343 634.5,-343 634.5,-307 788.5,-307 788.5,-343"/>
-<text text-anchor="middle" x="711.5" y="-321.3" font-family="Times,serif" font-size="14.00">internal/confui_sign.sock</text>
+<polygon fill="none" stroke="red" points="1085.5,-354 931.5,-354 931.5,-318 1085.5,-318 1085.5,-354"/>
+<text text-anchor="middle" x="1008.5" y="-332.3" font-family="Times,serif" font-size="14.00">internal/confui_sign.sock</text>
 </g>
 <!-- confirmationui_sign&#45;&gt;webRTC -->
 <g id="edge10" class="edge">
 <title>confirmationui_sign&#45;&gt;webRTC</title>
-<path fill="none" stroke="red" d="M798.79,-325C816.4,-325 834.02,-325 851.64,-325"/>
-<polygon fill="red" stroke="red" points="798.78,-321.5 788.78,-325 798.78,-328.5 798.78,-321.5"/>
-<polygon fill="red" stroke="red" points="852.01,-328.5 862.01,-325 852.01,-321.5 852.01,-328.5"/>
+<path fill="none" stroke="red" d="M1095.81,-336C1143.44,-336 1191.08,-336 1238.71,-336"/>
+<polygon fill="red" stroke="red" points="1095.61,-332.5 1085.61,-336 1095.61,-339.5 1095.61,-332.5"/>
+<polygon fill="red" stroke="red" points="1238.87,-339.5 1248.87,-336 1238.87,-332.5 1238.87,-339.5"/>
 </g>
 <!-- run_cvd -->
 <g id="node3" class="node">
 <title>run_cvd</title>
-<ellipse fill="none" stroke="black" cx="502.5" cy="-397" rx="39.79" ry="18"/>
-<text text-anchor="middle" x="502.5" y="-393.3" font-family="Times,serif" font-size="14.00">run_cvd</text>
+<ellipse fill="none" stroke="black" cx="709.5" cy="-408" rx="39.79" ry="18"/>
+<text text-anchor="middle" x="709.5" y="-404.3" font-family="Times,serif" font-size="14.00">run_cvd</text>
 </g>
 <!-- secure_env -->
 <g id="node4" class="node">
 <title>secure_env</title>
-<ellipse fill="none" stroke="black" stroke-width="2" cx="502.5" cy="-325" rx="57.39" ry="18"/>
-<text text-anchor="start" x="466.5" y="-322.3" font-family="Times,serif" font-size="14.00"> </text>
-<text text-anchor="start" x="470.5" y="-322.3" font-family="Times,serif" font-weight="bold" font-size="14.00">secure_env</text>
-<text text-anchor="start" x="534.5" y="-322.3" font-family="Times,serif" font-size="14.00"> </text>
+<ellipse fill="none" stroke="black" stroke-width="2" cx="709.5" cy="-336" rx="57.39" ry="18"/>
+<text text-anchor="start" x="673.5" y="-333.3" font-family="Times,serif" font-size="14.00"> </text>
+<text text-anchor="start" x="677.5" y="-333.3" font-family="Times,serif" font-weight="bold" font-size="14.00">secure_env</text>
+<text text-anchor="start" x="741.5" y="-333.3" font-family="Times,serif" font-size="14.00"> </text>
 </g>
 <!-- run_cvd&#45;&gt;secure_env -->
 <g id="edge2" class="edge">
 <title>run_cvd&#45;&gt;secure_env</title>
-<path fill="none" stroke="black" d="M502.5,-378.7C502.5,-370.98 502.5,-361.71 502.5,-353.11"/>
-<polygon fill="black" stroke="black" points="506,-353.1 502.5,-343.1 499,-353.1 506,-353.1"/>
+<path fill="none" stroke="black" d="M709.5,-389.7C709.5,-381.98 709.5,-372.71 709.5,-364.11"/>
+<polygon fill="black" stroke="black" points="713,-364.1 709.5,-354.1 706,-364.1 713,-364.1"/>
 </g>
 <!-- secure_env&#45;&gt;confirmationui_sign -->
 <g id="edge9" class="edge">
 <title>secure_env&#45;&gt;confirmationui_sign</title>
-<path fill="none" stroke="red" d="M570.21,-325C588.23,-325 606.26,-325 624.28,-325"/>
-<polygon fill="red" stroke="red" points="570.06,-321.5 560.06,-325 570.06,-328.5 570.06,-321.5"/>
-<polygon fill="red" stroke="red" points="624.3,-328.5 634.3,-325 624.3,-321.5 624.3,-328.5"/>
+<path fill="none" stroke="red" d="M777,-336C824.94,-336 872.89,-336 920.83,-336"/>
+<polygon fill="red" stroke="red" points="776.73,-332.5 766.73,-336 776.73,-339.5 776.73,-332.5"/>
+<polygon fill="red" stroke="red" points="921.06,-339.5 931.06,-336 921.06,-332.5 921.06,-339.5"/>
 </g>
-<!-- host_keymint_in -->
+<!-- host_keymaster_in -->
 <g id="node7" class="node">
-<title>host_keymint_in</title>
-<polygon fill="none" stroke="blue" points="183,-271 0,-271 0,-235 183,-235 183,-271"/>
-<text text-anchor="middle" x="91.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/keymaster_fifo_vm.in</text>
+<title>host_keymaster_in</title>
+<polygon fill="none" stroke="blue" points="183,-282 0,-282 0,-246 183,-246 183,-282"/>
+<text text-anchor="middle" x="91.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/keymaster_fifo_vm.in</text>
 </g>
-<!-- secure_env&#45;&gt;host_keymint_in -->
+<!-- secure_env&#45;&gt;host_keymaster_in -->
 <g id="edge19" class="edge">
-<title>secure_env&#45;&gt;host_keymint_in</title>
-<path fill="none" stroke="blue" d="M453.33,-315.63C389.35,-304.73 275.95,-285.41 193.11,-271.31"/>
-<polygon fill="blue" stroke="blue" points="193.61,-267.84 183.17,-269.61 192.44,-274.74 193.61,-267.84"/>
+<title>secure_env&#45;&gt;host_keymaster_in</title>
+<path fill="none" stroke="blue" d="M654.65,-330.55C561.89,-322.77 367.94,-305.39 193.27,-282.05"/>
+<polygon fill="blue" stroke="blue" points="193.5,-278.55 183.12,-280.69 192.56,-285.49 193.5,-278.55"/>
 </g>
-<!-- host_keymint_out -->
+<!-- host_keymaster_out -->
 <g id="node8" class="node">
-<title>host_keymint_out</title>
-<polygon fill="none" stroke="blue" points="391.5,-271 201.5,-271 201.5,-235 391.5,-235 391.5,-271"/>
-<text text-anchor="middle" x="296.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/keymaster_fifo_vm.out</text>
+<title>host_keymaster_out</title>
+<polygon fill="none" stroke="blue" points="391.5,-282 201.5,-282 201.5,-246 391.5,-246 391.5,-282"/>
+<text text-anchor="middle" x="296.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/keymaster_fifo_vm.out</text>
 </g>
-<!-- secure_env&#45;&gt;host_keymint_out -->
+<!-- secure_env&#45;&gt;host_keymaster_out -->
 <g id="edge17" class="edge">
-<title>secure_env&#45;&gt;host_keymint_out</title>
-<path fill="none" stroke="blue" d="M455.48,-308.02C423,-296.99 379.85,-282.32 346.71,-271.06"/>
-<polygon fill="blue" stroke="blue" points="454.6,-311.42 465.19,-311.32 456.85,-304.79 454.6,-311.42"/>
+<title>secure_env&#45;&gt;host_keymaster_out</title>
+<path fill="none" stroke="blue" d="M650.46,-324.99C582.95,-313.55 471.47,-294.66 391.65,-281.13"/>
+<polygon fill="blue" stroke="blue" points="650.06,-328.47 660.5,-326.7 651.23,-321.57 650.06,-328.47"/>
 </g>
 <!-- host_gatekeeper_in -->
 <g id="node9" class="node">
 <title>host_gatekeeper_in</title>
-<polygon fill="none" stroke="green" points="595,-271 410,-271 410,-235 595,-235 595,-271"/>
-<text text-anchor="middle" x="502.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/gatekeeper_fifo_vm.in</text>
+<polygon fill="none" stroke="green" points="595,-282 410,-282 410,-246 595,-246 595,-282"/>
+<text text-anchor="middle" x="502.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/gatekeeper_fifo_vm.in</text>
 </g>
 <!-- secure_env&#45;&gt;host_gatekeeper_in -->
 <g id="edge13" class="edge">
 <title>secure_env&#45;&gt;host_gatekeeper_in</title>
-<path fill="none" stroke="green" d="M502.5,-306.7C502.5,-298.98 502.5,-289.71 502.5,-281.11"/>
-<polygon fill="green" stroke="green" points="506,-281.1 502.5,-271.1 499,-281.1 506,-281.1"/>
+<path fill="none" stroke="green" d="M672.01,-322.32C641.56,-312.02 598.01,-297.3 562.68,-285.35"/>
+<polygon fill="green" stroke="green" points="563.54,-281.95 552.95,-282.06 561.3,-288.58 563.54,-281.95"/>
 </g>
 <!-- host_gatekeeper_out -->
 <g id="node10" class="node">
 <title>host_gatekeeper_out</title>
-<polygon fill="none" stroke="green" points="805.5,-271 613.5,-271 613.5,-235 805.5,-235 805.5,-271"/>
-<text text-anchor="middle" x="709.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/gatekeeper_fifo_vm.out</text>
+<polygon fill="none" stroke="green" points="805.5,-282 613.5,-282 613.5,-246 805.5,-246 805.5,-282"/>
+<text text-anchor="middle" x="709.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/gatekeeper_fifo_vm.out</text>
 </g>
 <!-- secure_env&#45;&gt;host_gatekeeper_out -->
 <g id="edge11" class="edge">
 <title>secure_env&#45;&gt;host_gatekeeper_out</title>
-<path fill="none" stroke="green" d="M549.75,-308.02C582.38,-296.99 625.74,-282.32 659.05,-271.06"/>
-<polygon fill="green" stroke="green" points="548.34,-304.8 539.99,-311.32 550.58,-311.44 548.34,-304.8"/>
+<path fill="none" stroke="green" d="M709.5,-307.67C709.5,-299.05 709.5,-289.79 709.5,-282.1"/>
+<polygon fill="green" stroke="green" points="706,-307.7 709.5,-317.7 713,-307.7 706,-307.7"/>
+</g>
+<!-- host_keymint_in -->
+<g id="node13" class="node">
+<title>host_keymint_in</title>
+<polygon fill="none" stroke="blue" points="995.5,-282 823.5,-282 823.5,-246 995.5,-246 995.5,-282"/>
+<text text-anchor="middle" x="909.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/keymint_fifo_vm.in</text>
+</g>
+<!-- secure_env&#45;&gt;host_keymint_in -->
+<g id="edge26" class="edge">
+<title>secure_env&#45;&gt;host_keymint_in</title>
+<path fill="none" stroke="blue" d="M746.18,-322.16C775.44,-311.92 816.97,-297.39 850.83,-285.54"/>
+<polygon fill="blue" stroke="blue" points="852.33,-288.72 860.61,-282.11 850.02,-282.11 852.33,-288.72"/>
+</g>
+<!-- host_keymint_out -->
+<g id="node14" class="node">
+<title>host_keymint_out</title>
+<polygon fill="none" stroke="blue" points="1193,-282 1014,-282 1014,-246 1193,-246 1193,-282"/>
+<text text-anchor="middle" x="1103.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/keymint_fifo_vm.out</text>
+</g>
+<!-- secure_env&#45;&gt;host_keymint_out -->
+<g id="edge24" class="edge">
+<title>secure_env&#45;&gt;host_keymint_out</title>
+<path fill="none" stroke="blue" d="M768.27,-324.56C833.18,-313.03 938.45,-294.32 1013.71,-280.95"/>
+<polygon fill="blue" stroke="blue" points="767.44,-321.15 758.21,-326.35 768.67,-328.04 767.44,-321.15"/>
 </g>
 <!-- vmm -->
 <g id="node5" class="node">
 <title>vmm</title>
-<ellipse fill="none" stroke="black" cx="605.5" cy="-181" rx="64.19" ry="18"/>
-<text text-anchor="middle" x="605.5" y="-177.3" font-family="Times,serif" font-size="14.00">crosvm / qemu</text>
+<ellipse fill="none" stroke="black" cx="809.5" cy="-192" rx="64.19" ry="18"/>
+<text text-anchor="middle" x="809.5" y="-188.3" font-family="Times,serif" font-size="14.00">crosvm / qemu</text>
 </g>
 <!-- confirmationui_console -->
-<g id="node17" class="node">
+<g id="node20" class="node">
 <title>confirmationui_console</title>
-<polygon fill="none" stroke="red" points="773.5,-124 703.5,-124 703.5,-88 773.5,-88 773.5,-124"/>
-<text text-anchor="middle" x="738.5" y="-102.3" font-family="Times,serif" font-size="14.00">/dev/hvc8</text>
+<polygon fill="none" stroke="red" points="1039.5,-135 969.5,-135 969.5,-99 1039.5,-99 1039.5,-135"/>
+<text text-anchor="middle" x="1004.5" y="-113.3" font-family="Times,serif" font-size="14.00">/dev/hvc8</text>
 </g>
 <!-- vmm&#45;&gt;confirmationui_console -->
 <g id="edge7" class="edge">
 <title>vmm&#45;&gt;confirmationui_console</title>
-<path fill="none" stroke="red" d="M642.4,-159.74C659.81,-150.19 680.61,-138.77 698.4,-129.01"/>
-<polygon fill="red" stroke="red" points="640.46,-156.82 633.38,-164.7 643.83,-162.95 640.46,-156.82"/>
-<polygon fill="red" stroke="red" points="700.32,-131.95 707.4,-124.07 696.95,-125.81 700.32,-131.95"/>
+<path fill="none" stroke="red" d="M868.88,-177.74C881.45,-174.36 894.53,-170.42 906.5,-166 926.14,-158.74 947.09,-148.81 964.56,-139.85"/>
+<polygon fill="red" stroke="red" points="867.74,-174.42 858.95,-180.32 869.5,-181.19 867.74,-174.42"/>
+<polygon fill="red" stroke="red" points="966.62,-142.73 973.87,-135.01 963.39,-136.52 966.62,-142.73"/>
 </g>
 <!-- gatekeeper_console -->
-<g id="node18" class="node">
+<g id="node21" class="node">
 <title>gatekeeper_console</title>
-<polygon fill="none" stroke="green" points="640.5,-124 570.5,-124 570.5,-88 640.5,-88 640.5,-124"/>
-<text text-anchor="middle" x="605.5" y="-102.3" font-family="Times,serif" font-size="14.00">/dev/hvc4</text>
+<polygon fill="none" stroke="green" points="897.5,-135 827.5,-135 827.5,-99 897.5,-99 897.5,-135"/>
+<text text-anchor="middle" x="862.5" y="-113.3" font-family="Times,serif" font-size="14.00">/dev/hvc4</text>
 </g>
 <!-- vmm&#45;&gt;gatekeeper_console -->
 <g id="edge15" class="edge">
 <title>vmm&#45;&gt;gatekeeper_console</title>
-<path fill="none" stroke="green" d="M605.5,-152.49C605.5,-146.55 605.5,-140.27 605.5,-134.33"/>
-<polygon fill="green" stroke="green" points="602,-152.7 605.5,-162.7 609,-152.7 602,-152.7"/>
-<polygon fill="green" stroke="green" points="609,-134.18 605.5,-124.18 602,-134.18 609,-134.18"/>
+<path fill="none" stroke="green" d="M827.71,-165.92C833.02,-158.61 838.82,-150.62 844.13,-143.3"/>
+<polygon fill="green" stroke="green" points="824.84,-163.92 821.79,-174.07 830.5,-168.03 824.84,-163.92"/>
+<polygon fill="green" stroke="green" points="847.05,-145.24 850.09,-135.09 841.38,-141.13 847.05,-145.24"/>
+</g>
+<!-- keymaster_console -->
+<g id="node22" class="node">
+<title>keymaster_console</title>
+<polygon fill="none" stroke="blue" points="792.5,-135 722.5,-135 722.5,-99 792.5,-99 792.5,-135"/>
+<text text-anchor="middle" x="757.5" y="-113.3" font-family="Times,serif" font-size="14.00">/dev/hvc3</text>
+</g>
+<!-- vmm&#45;&gt;keymaster_console -->
+<g id="edge21" class="edge">
+<title>vmm&#45;&gt;keymaster_console</title>
+<path fill="none" stroke="blue" d="M791.63,-165.92C786.43,-158.61 780.74,-150.62 775.52,-143.3"/>
+<polygon fill="blue" stroke="blue" points="788.79,-167.95 797.44,-174.07 794.49,-163.89 788.79,-167.95"/>
+<polygon fill="blue" stroke="blue" points="778.33,-141.21 769.68,-135.09 772.63,-145.27 778.33,-141.21"/>
 </g>
 <!-- keymint_console -->
-<g id="node19" class="node">
+<g id="node23" class="node">
 <title>keymint_console</title>
-<polygon fill="none" stroke="blue" points="488.5,-124 418.5,-124 418.5,-88 488.5,-88 488.5,-124"/>
-<text text-anchor="middle" x="453.5" y="-102.3" font-family="Times,serif" font-size="14.00">/dev/hvc3</text>
+<polygon fill="none" stroke="blue" points="583,-135 506,-135 506,-99 583,-99 583,-135"/>
+<text text-anchor="middle" x="544.5" y="-113.3" font-family="Times,serif" font-size="14.00">/dev/hvc11</text>
 </g>
 <!-- vmm&#45;&gt;keymint_console -->
-<g id="edge21" class="edge">
+<g id="edge28" class="edge">
 <title>vmm&#45;&gt;keymint_console</title>
-<path fill="none" stroke="blue" d="M565.23,-160.66C544.45,-150.68 519.06,-138.49 497.74,-128.25"/>
-<polygon fill="blue" stroke="blue" points="563.84,-163.88 574.37,-165.05 566.87,-157.57 563.84,-163.88"/>
-<polygon fill="blue" stroke="blue" points="499.1,-125.02 488.57,-123.84 496.07,-131.33 499.1,-125.02"/>
+<path fill="none" stroke="blue" d="M753.65,-176.68C740.47,-173.24 726.48,-169.53 713.5,-166 672.65,-154.88 626.42,-141.71 592.65,-131.98"/>
+<polygon fill="blue" stroke="blue" points="752.99,-180.12 763.54,-179.25 754.75,-173.35 752.99,-180.12"/>
+<polygon fill="blue" stroke="blue" points="593.61,-128.61 583.03,-129.2 591.67,-135.34 593.61,-128.61"/>
 </g>
 <!-- host_confirmationui_in -->
 <g id="node11" class="node">
 <title>host_confirmationui_in</title>
-<polygon fill="none" stroke="red" points="985,-271 824,-271 824,-235 985,-235 985,-271"/>
-<text text-anchor="middle" x="904.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/confui_fifo_vm.in</text>
+<polygon fill="none" stroke="red" points="1372,-282 1211,-282 1211,-246 1372,-246 1372,-282"/>
+<text text-anchor="middle" x="1291.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/confui_fifo_vm.in</text>
 </g>
 <!-- webRTC&#45;&gt;host_confirmationui_in -->
 <g id="edge5" class="edge">
 <title>webRTC&#45;&gt;host_confirmationui_in</title>
-<path fill="none" stroke="red" d="M904.5,-306.7C904.5,-298.98 904.5,-289.71 904.5,-281.11"/>
-<polygon fill="red" stroke="red" points="908,-281.1 904.5,-271.1 901,-281.1 908,-281.1"/>
+<path fill="none" stroke="red" d="M1291.5,-317.7C1291.5,-309.98 1291.5,-300.71 1291.5,-292.11"/>
+<polygon fill="red" stroke="red" points="1295,-292.1 1291.5,-282.1 1288,-292.1 1295,-292.1"/>
 </g>
 <!-- host_confirmationui_out -->
 <g id="node12" class="node">
 <title>host_confirmationui_out</title>
-<polygon fill="none" stroke="red" points="1171.5,-271 1003.5,-271 1003.5,-235 1171.5,-235 1171.5,-271"/>
-<text text-anchor="middle" x="1087.5" y="-249.3" font-family="Times,serif" font-size="14.00">internal/confui_fifo_vm.out</text>
+<polygon fill="none" stroke="red" points="1558.5,-282 1390.5,-282 1390.5,-246 1558.5,-246 1558.5,-282"/>
+<text text-anchor="middle" x="1474.5" y="-260.3" font-family="Times,serif" font-size="14.00">internal/confui_fifo_vm.out</text>
 </g>
 <!-- webRTC&#45;&gt;host_confirmationui_out -->
 <g id="edge3" class="edge">
 <title>webRTC&#45;&gt;host_confirmationui_out</title>
-<path fill="none" stroke="red" d="M944.57,-308.67C973.65,-297.55 1013,-282.5 1043.05,-271"/>
-<polygon fill="red" stroke="red" points="943.22,-305.44 935.13,-312.28 945.72,-311.98 943.22,-305.44"/>
+<path fill="none" stroke="red" d="M1331.57,-319.67C1360.65,-308.55 1400,-293.5 1430.05,-282"/>
+<polygon fill="red" stroke="red" points="1330.22,-316.44 1322.13,-323.28 1332.72,-322.98 1330.22,-316.44"/>
 </g>
-<!-- host_keymint_in&#45;&gt;vmm -->
+<!-- host_keymaster_in&#45;&gt;vmm -->
 <g id="edge20" class="edge">
-<title>host_keymint_in&#45;&gt;vmm</title>
-<path fill="none" stroke="blue" d="M183.13,-236.42C186.29,-235.93 189.42,-235.46 192.5,-235 313.66,-217.04 455.35,-199.63 537.32,-189.92"/>
-<polygon fill="blue" stroke="blue" points="537.74,-193.4 547.26,-188.75 536.92,-186.44 537.74,-193.4"/>
+<title>host_keymaster_in&#45;&gt;vmm</title>
+<path fill="none" stroke="blue" d="M183.11,-247.25C186.28,-246.81 189.41,-246.39 192.5,-246 388.69,-221.1 621.5,-204.62 737.01,-197.32"/>
+<polygon fill="blue" stroke="blue" points="737.38,-200.8 747.14,-196.68 736.94,-193.81 737.38,-200.8"/>
 </g>
-<!-- host_keymint_out&#45;&gt;vmm -->
+<!-- host_keymaster_out&#45;&gt;vmm -->
 <g id="edge18" class="edge">
-<title>host_keymint_out&#45;&gt;vmm</title>
-<path fill="none" stroke="blue" d="M381.69,-232.7C438.14,-219.91 510.16,-203.6 557.03,-192.98"/>
-<polygon fill="blue" stroke="blue" points="380.67,-229.34 371.69,-234.97 382.22,-236.17 380.67,-229.34"/>
+<title>host_keymaster_out&#45;&gt;vmm</title>
+<path fill="none" stroke="blue" d="M402.02,-245.95C533.47,-226.91 674.52,-209.31 751.65,-199.94"/>
+<polygon fill="blue" stroke="blue" points="401.16,-242.54 391.77,-247.44 402.17,-249.47 401.16,-242.54"/>
 </g>
 <!-- host_gatekeeper_in&#45;&gt;vmm -->
 <g id="edge14" class="edge">
 <title>host_gatekeeper_in&#45;&gt;vmm</title>
-<path fill="none" stroke="green" d="M527.7,-234.88C541.54,-225.47 558.84,-213.71 573.62,-203.67"/>
-<polygon fill="green" stroke="green" points="575.67,-206.5 581.98,-197.99 571.74,-200.71 575.67,-206.5"/>
+<path fill="none" stroke="green" d="M577.21,-245.97C630.84,-233.74 702.08,-217.49 751.46,-206.23"/>
+<polygon fill="green" stroke="green" points="752.37,-209.62 761.34,-203.98 750.82,-202.79 752.37,-209.62"/>
 </g>
 <!-- host_gatekeeper_out&#45;&gt;vmm -->
 <g id="edge12" class="edge">
 <title>host_gatekeeper_out&#45;&gt;vmm</title>
-<path fill="none" stroke="green" d="M675.47,-229.1C660.36,-218.92 642.93,-207.2 629.25,-197.99"/>
-<polygon fill="green" stroke="green" points="673.81,-232.2 684.06,-234.88 677.72,-226.39 673.81,-232.2"/>
+<path fill="none" stroke="green" d="M742.22,-240.1C756.75,-229.92 773.51,-218.2 786.66,-208.99"/>
+<polygon fill="green" stroke="green" points="740.15,-237.27 733.96,-245.88 744.16,-243.01 740.15,-237.27"/>
 </g>
 <!-- host_confirmationui_in&#45;&gt;vmm -->
 <g id="edge6" class="edge">
 <title>host_confirmationui_in&#45;&gt;vmm</title>
-<path fill="none" stroke="red" d="M831.74,-234.97C779.94,-222.84 711.27,-206.76 663.22,-195.51"/>
-<polygon fill="red" stroke="red" points="663.83,-192.06 653.3,-193.19 662.24,-198.88 663.83,-192.06"/>
+<path fill="none" stroke="red" d="M1210.53,-247.34C1207.82,-246.88 1205.14,-246.43 1202.5,-246 1089.02,-227.52 956.35,-210.6 877.82,-201.06"/>
+<polygon fill="red" stroke="red" points="877.93,-197.55 867.58,-199.82 877.09,-204.5 877.93,-197.55"/>
 </g>
 <!-- host_confirmationui_out&#45;&gt;vmm -->
 <g id="edge4" class="edge">
 <title>host_confirmationui_out&#45;&gt;vmm</title>
-<path fill="none" stroke="red" d="M993.38,-234.86C869.99,-215.37 737.36,-198.25 663.29,-189.04"/>
-<polygon fill="red" stroke="red" points="992.95,-238.33 1003.38,-236.45 994.05,-231.42 992.95,-238.33"/>
+<path fill="none" stroke="red" d="M1380.45,-245.92C1189.25,-220.04 974.89,-203.91 871.5,-196.94"/>
+<polygon fill="red" stroke="red" points="1380.02,-249.4 1390.4,-247.28 1380.97,-242.46 1380.02,-249.4"/>
+</g>
+<!-- host_keymint_in&#45;&gt;vmm -->
+<g id="edge27" class="edge">
+<title>host_keymint_in&#45;&gt;vmm</title>
+<path fill="none" stroke="blue" d="M885.04,-245.88C871.73,-236.56 855.11,-224.93 840.86,-214.95"/>
+<polygon fill="blue" stroke="blue" points="842.54,-211.85 832.34,-208.99 838.52,-217.59 842.54,-211.85"/>
+</g>
+<!-- host_keymint_out&#45;&gt;vmm -->
+<g id="edge25" class="edge">
+<title>host_keymint_out&#45;&gt;vmm</title>
+<path fill="none" stroke="blue" d="M1022.21,-243.64C969.06,-230.99 901.49,-214.9 856.94,-204.3"/>
+<polygon fill="blue" stroke="blue" points="1021.42,-247.05 1031.96,-245.97 1023.04,-240.24 1021.42,-247.05"/>
 </g>
 <!-- u_boot -->
-<g id="node13" class="node">
+<g id="node15" class="node">
 <title>u_boot</title>
-<ellipse fill="none" stroke="black" cx="339.5" cy="-34" rx="33.6" ry="18"/>
-<text text-anchor="middle" x="339.5" y="-30.3" font-family="Times,serif" font-size="14.00">u&#45;boot</text>
+<ellipse fill="none" stroke="black" cx="757.5" cy="-42" rx="33.6" ry="18"/>
+<text text-anchor="middle" x="757.5" y="-38.3" font-family="Times,serif" font-size="14.00">u&#45;boot</text>
 </g>
 <!-- confirmationui -->
-<g id="node14" class="node">
+<g id="node16" class="node">
 <title>confirmationui</title>
-<ellipse fill="none" stroke="red" cx="783.5" cy="-34" rx="88.28" ry="18"/>
-<text text-anchor="middle" x="783.5" y="-30.3" font-family="Times,serif" font-size="14.00">ConfirmationUI HAL</text>
+<ellipse fill="none" stroke="red" cx="1058.5" cy="-42" rx="88.28" ry="18"/>
+<text text-anchor="middle" x="1058.5" y="-38.3" font-family="Times,serif" font-size="14.00">ConfirmationUI HAL</text>
 </g>
 <!-- gatekeeper -->
-<g id="node15" class="node">
+<g id="node17" class="node">
 <title>gatekeeper</title>
-<ellipse fill="none" stroke="green" cx="605.5" cy="-34" rx="71.49" ry="18"/>
-<text text-anchor="middle" x="605.5" y="-30.3" font-family="Times,serif" font-size="14.00">Gatekeeper HAL</text>
+<ellipse fill="none" stroke="green" cx="880.5" cy="-42" rx="71.49" ry="18"/>
+<text text-anchor="middle" x="880.5" y="-38.3" font-family="Times,serif" font-size="14.00">Gatekeeper HAL</text>
+</g>
+<!-- keymaster -->
+<g id="node18" class="node">
+<title>keymaster</title>
+<ellipse fill="none" stroke="blue" cx="617.5" cy="-42" rx="88.28" ry="18"/>
+<text text-anchor="middle" x="617.5" y="-38.3" font-family="Times,serif" font-size="14.00">KeyMint (C++) HAL</text>
 </g>
 <!-- keymint -->
-<g id="node16" class="node">
+<g id="node19" class="node">
 <title>keymint</title>
-<ellipse fill="none" stroke="blue" cx="453.5" cy="-34" rx="62.29" ry="18"/>
-<text text-anchor="middle" x="453.5" y="-30.3" font-family="Times,serif" font-size="14.00">Keymint HAL</text>
+<ellipse fill="none" stroke="blue" cx="423.5" cy="-42" rx="87.99" ry="18"/>
+<text text-anchor="middle" x="423.5" y="-38.3" font-family="Times,serif" font-size="14.00">KeyMint (Rust) HAL</text>
 </g>
 <!-- confirmationui_console&#45;&gt;confirmationui -->
 <g id="edge8" class="edge">
 <title>confirmationui_console&#45;&gt;confirmationui</title>
-<path fill="none" stroke="red" d="M755.16,-79.08C759.05,-73.03 763.19,-66.59 767.07,-60.56"/>
-<polygon fill="red" stroke="red" points="752.09,-77.39 749.62,-87.7 757.98,-81.18 752.09,-77.39"/>
-<polygon fill="red" stroke="red" points="770.04,-62.41 772.5,-52.1 764.15,-58.62 770.04,-62.41"/>
+<path fill="none" stroke="red" d="M1023.32,-90.56C1028.71,-83.27 1034.58,-75.33 1039.96,-68.06"/>
+<polygon fill="red" stroke="red" points="1020.43,-88.58 1017.3,-98.7 1026.06,-92.74 1020.43,-88.58"/>
+<polygon fill="red" stroke="red" points="1042.85,-70.04 1045.98,-59.92 1037.22,-65.88 1042.85,-70.04"/>
 </g>
 <!-- gatekeeper_console&#45;&gt;gatekeeper -->
 <g id="edge16" class="edge">
 <title>gatekeeper_console&#45;&gt;gatekeeper</title>
-<path fill="none" stroke="green" d="M605.5,-77.67C605.5,-72.69 605.5,-67.49 605.5,-62.51"/>
-<polygon fill="green" stroke="green" points="602,-77.7 605.5,-87.7 609,-77.7 602,-77.7"/>
-<polygon fill="green" stroke="green" points="609,-62.1 605.5,-52.1 602,-62.1 609,-62.1"/>
+<path fill="none" stroke="green" d="M869.21,-88.79C870.72,-82.65 872.33,-76.13 873.84,-70"/>
+<polygon fill="green" stroke="green" points="865.76,-88.15 866.77,-98.7 872.56,-89.83 865.76,-88.15"/>
+<polygon fill="green" stroke="green" points="877.27,-70.72 876.26,-60.18 870.47,-69.05 877.27,-70.72"/>
 </g>
-<!-- keymint_console&#45;&gt;u_boot -->
+<!-- keymaster_console&#45;&gt;u_boot -->
 <g id="edge23" class="edge">
-<title>keymint_console&#45;&gt;u_boot</title>
-<path fill="none" stroke="blue" d="M416.87,-82.51C401.61,-73.14 384.11,-62.39 369.62,-53.49"/>
-<polygon fill="blue" stroke="blue" points="415.26,-85.63 425.61,-87.88 418.92,-79.66 415.26,-85.63"/>
-<polygon fill="blue" stroke="blue" points="371.38,-50.47 361.03,-48.22 367.72,-56.44 371.38,-50.47"/>
+<title>keymaster_console&#45;&gt;u_boot</title>
+<path fill="none" stroke="blue" d="M757.5,-88.49C757.5,-82.55 757.5,-76.27 757.5,-70.33"/>
+<polygon fill="blue" stroke="blue" points="754,-88.7 757.5,-98.7 761,-88.7 754,-88.7"/>
+<polygon fill="blue" stroke="blue" points="761,-70.18 757.5,-60.18 754,-70.18 761,-70.18"/>
+</g>
+<!-- keymaster_console&#45;&gt;keymaster -->
+<g id="edge22" class="edge">
+<title>keymaster_console&#45;&gt;keymaster</title>
+<path fill="none" stroke="blue" d="M715.61,-94.18C713.54,-93.11 711.5,-92.04 709.5,-91 692.41,-82.09 673.53,-72.24 657.35,-63.8"/>
+<polygon fill="blue" stroke="blue" points="714.22,-97.41 724.71,-98.92 717.46,-91.2 714.22,-97.41"/>
+<polygon fill="blue" stroke="blue" points="658.65,-60.53 648.16,-59.01 655.41,-66.73 658.65,-60.53"/>
 </g>
 <!-- keymint_console&#45;&gt;keymint -->
-<g id="edge22" class="edge">
+<g id="edge29" class="edge">
 <title>keymint_console&#45;&gt;keymint</title>
-<path fill="none" stroke="blue" d="M453.5,-77.67C453.5,-72.69 453.5,-67.49 453.5,-62.51"/>
-<polygon fill="blue" stroke="blue" points="450,-77.7 453.5,-87.7 457,-77.7 450,-77.7"/>
-<polygon fill="blue" stroke="blue" points="457,-62.1 453.5,-52.1 450,-62.1 457,-62.1"/>
+<path fill="none" stroke="blue" d="M507.41,-93.63C492.04,-84.35 474.28,-73.64 459.07,-64.46"/>
+<polygon fill="blue" stroke="blue" points="505.76,-96.72 516.13,-98.88 509.38,-90.72 505.76,-96.72"/>
+<polygon fill="blue" stroke="blue" points="460.82,-61.43 450.45,-59.26 457.2,-67.42 460.82,-61.43"/>
 </g>
 </g>
 </svg>
diff --git a/host/commands/secure_env/oemlock/oemlock.cpp b/host/commands/secure_env/oemlock/oemlock.cpp
new file mode 100644
index 0000000..05709f6
--- /dev/null
+++ b/host/commands/secure_env/oemlock/oemlock.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2023 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.
+ *
+ */
+
+#include "host/commands/secure_env/oemlock/oemlock.h"
+
+namespace cuttlefish {
+namespace oemlock {
+namespace {
+
+constexpr char kStateKey[] = "oemlock_state";
+constexpr int kAllowedByCarrierBit = 0;
+constexpr int kAllowedByDeviceBit = 1;
+constexpr int kOemLockedBit = 2;
+
+// Default state is allowed_by_carrier = true
+//                  allowed_by_device = false
+//                  locked = true
+constexpr uint8_t kDefaultState = 0 | (1 << kAllowedByCarrierBit) | (1 << kOemLockedBit);
+
+Result<void> InitializeDefaultState(secure_env::Storage& storage) {
+  if (storage.Exists()) { return {}; };
+  auto data = CF_EXPECT(secure_env::CreateStorageData(&kDefaultState, sizeof(kDefaultState)));
+  CF_EXPECT(storage.Write(kStateKey, *data));
+  return {};
+}
+
+Result<bool> ReadFlag(secure_env::Storage& storage, int bit) {
+  auto data = CF_EXPECT(storage.Read(kStateKey));
+  auto state = CF_EXPECT(data->asUint8());
+  return (state >> bit) & 1;
+}
+
+Result<void> WriteFlag(secure_env::Storage& storage, int bit, bool value) {
+  auto data = CF_EXPECT(storage.Read(kStateKey));
+  auto state = CF_EXPECT(data->asUint8());
+  value ? state |= (1 << bit) : state &= ~(1 << bit);
+  auto data_to_write = CF_EXPECT(secure_env::CreateStorageData(&state, sizeof(state)));
+  CF_EXPECT(storage.Write(kStateKey, *data_to_write));
+  return {};
+}
+
+} // namespace
+
+OemLock::OemLock(secure_env::Storage& storage) : storage_(storage) {
+  auto result = InitializeDefaultState(storage_);
+  if (!result.ok()) {
+    LOG(FATAL) << "Failed to initialize default state for OemLock TEE storage: "
+               << result.error().Message();
+  }
+}
+
+Result<bool> OemLock::IsOemUnlockAllowedByCarrier() const {
+  return CF_EXPECT(ReadFlag(storage_, kAllowedByCarrierBit));
+}
+
+Result<bool> OemLock::IsOemUnlockAllowedByDevice() const {
+  return CF_EXPECT(ReadFlag(storage_, kAllowedByDeviceBit));
+}
+
+Result<bool> OemLock::IsOemUnlockAllowed() const {
+  auto data = CF_EXPECT(storage_.Read(kStateKey));
+  auto state = CF_EXPECT(data->asUint8());
+  const bool allowed_by_device = (state >> kAllowedByDeviceBit) & 1;
+  const bool allowed_by_carrier = (state >> kAllowedByCarrierBit) & 1;
+  return allowed_by_device && allowed_by_carrier;
+}
+
+Result<bool> OemLock::IsOemLocked() const {
+  return CF_EXPECT(ReadFlag(storage_, kOemLockedBit));
+}
+
+Result<void> OemLock::SetOemUnlockAllowedByCarrier(bool allowed) {
+  CF_EXPECT(WriteFlag(storage_, kAllowedByCarrierBit, allowed));
+  return {};
+}
+
+Result<void> OemLock::SetOemUnlockAllowedByDevice(bool allowed) {
+  CF_EXPECT(WriteFlag(storage_, kAllowedByDeviceBit, allowed));
+  return {};
+}
+
+Result<void> OemLock::SetOemLocked(bool locked) {
+  CF_EXPECT(WriteFlag(storage_, kOemLockedBit, locked));
+  return {};
+}
+
+} // namespace oemlock
+} // namespace cuttlefish
\ No newline at end of file
diff --git a/host/commands/secure_env/oemlock/oemlock.h b/host/commands/secure_env/oemlock/oemlock.h
new file mode 100644
index 0000000..306ec78
--- /dev/null
+++ b/host/commands/secure_env/oemlock/oemlock.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2023 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.
+ *
+ */
+
+#pragma once
+
+#include "common/libs/utils/result.h"
+
+#include "host/commands/secure_env/storage/storage.h"
+
+namespace cuttlefish {
+namespace oemlock {
+
+/**
+ * OEMLock TPM server interface
+ *
+ * Inspired by OemLock HAL interface:
+ * https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/oemlock/aidl/default/Android.bp
+*/
+class OemLock {
+ public:
+  OemLock(secure_env::Storage& storage);
+
+  Result<bool> IsOemUnlockAllowedByCarrier() const;
+  Result<bool> IsOemUnlockAllowedByDevice() const;
+  Result<bool> IsOemUnlockAllowed() const;
+  Result<bool> IsOemLocked() const;
+  Result<void> SetOemUnlockAllowedByCarrier(bool allowed);
+  Result<void> SetOemUnlockAllowedByDevice(bool allowed);
+  // TODO(b/286558252): add ConfirmationUI token to the signature
+  Result<void> SetOemLocked(bool locked);
+
+ private:
+  secure_env::Storage& storage_;
+};
+
+} // namespace oemlock
+} // namespace cuttlefish
diff --git a/host/commands/secure_env/oemlock/oemlock_responder.cpp b/host/commands/secure_env/oemlock/oemlock_responder.cpp
new file mode 100644
index 0000000..be434ae
--- /dev/null
+++ b/host/commands/secure_env/oemlock/oemlock_responder.cpp
@@ -0,0 +1,83 @@
+//
+// Copyright (C) 2023 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.
+
+#include "host/commands/secure_env/oemlock/oemlock_responder.h"
+
+#include "common/libs/security/oemlock.h"
+
+namespace cuttlefish {
+namespace oemlock {
+
+OemLockResponder::OemLockResponder(secure_env::Channel& channel,
+                                   OemLock& oemlock)
+    : channel_(channel), oemlock_(oemlock) {}
+
+Result<void> OemLockResponder::ProcessMessage() {
+  auto request = CF_EXPECT(channel_.ReceiveMessage(), "Could not receive message");
+
+  bool result = false;
+  switch(secure_env::OemLockField(request->command)) {
+    case secure_env::OemLockField::ALLOWED_BY_CARRIER: {
+      if (request->payload_size == 0) {
+        result = CF_EXPECT(oemlock_.IsOemUnlockAllowedByCarrier());
+      } else if (request->payload_size == sizeof(bool)) {
+        result = *reinterpret_cast<bool*>(request->payload);
+        CF_EXPECT(oemlock_.SetOemUnlockAllowedByCarrier(result));
+      }
+      break;
+    }
+
+    case secure_env::OemLockField::ALLOWED_BY_DEVICE: {
+      if (request->payload_size == 0) {
+        result = CF_EXPECT(oemlock_.IsOemUnlockAllowedByDevice());
+      } else if (request->payload_size == sizeof(bool)) {
+        result = *reinterpret_cast<bool*>(request->payload);
+        CF_EXPECT(oemlock_.SetOemUnlockAllowedByDevice(result));
+      }
+      break;
+    }
+
+    case secure_env::OemLockField::ALLOWED: {
+      if (request->payload_size == 0) {
+        result = CF_EXPECT(oemlock_.IsOemUnlockAllowed());
+      }
+      break;
+    }
+
+    case secure_env::OemLockField::LOCKED: {
+      if (request->payload_size == 0) {
+        result = CF_EXPECT(oemlock_.IsOemLocked());
+      } else if (request->payload_size == sizeof(bool)) {
+        result = *reinterpret_cast<bool*>(request->payload);
+        CF_EXPECT(oemlock_.SetOemLocked(result));
+      }
+      break;
+    }
+
+    default:
+      return CF_ERR("Unrecognized message id " << reinterpret_cast<uint32_t>(request->command));
+  }
+
+  auto message = CF_EXPECT(secure_env::CreateMessage(request->command, sizeof(bool)),
+                           "Failed to allocate message for oemlock response");
+  memcpy(message->payload, &result, sizeof(bool));
+  CF_EXPECT(channel_.SendResponse(*message),
+            "Could not answer to " << reinterpret_cast<uint32_t>(request->command) << " request");
+
+  return {};
+}
+
+}  // namespace oemlock
+}  // namespace cuttlefish
diff --git a/host/commands/secure_env/oemlock/oemlock_responder.h b/host/commands/secure_env/oemlock/oemlock_responder.h
new file mode 100644
index 0000000..0b5fadb
--- /dev/null
+++ b/host/commands/secure_env/oemlock/oemlock_responder.h
@@ -0,0 +1,38 @@
+//
+// Copyright (C) 2023 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.
+
+#pragma once
+
+#include "common/libs/security/channel.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/secure_env/oemlock/oemlock.h"
+
+namespace cuttlefish {
+namespace oemlock {
+
+class OemLockResponder {
+ public:
+  OemLockResponder(secure_env::Channel& channel,
+                   OemLock& oemlock);
+
+  Result<void> ProcessMessage();
+
+ private:
+  secure_env::Channel& channel_;
+  OemLock& oemlock_;
+};
+
+}  // namespace oemlock
+}  // namespace cuttlefish
diff --git a/host/commands/secure_env/rust/lib.rs b/host/commands/secure_env/rust/lib.rs
index 4d4e2f4..71f0289 100644
--- a/host/commands/secure_env/rust/lib.rs
+++ b/host/commands/secure_env/rust/lib.rs
@@ -46,7 +46,7 @@
     log::set_logger(&AndroidCppLogger).unwrap();
     log::set_max_level(log::LevelFilter::Debug); // Filtering happens elsewhere
     info!(
-        "KeyMint TA running with fd_in={}, fd_out={}, security_level={:?}",
+        "KeyMint Rust TA running with fd_in={}, fd_out={}, security_level={:?}",
         fd_in, fd_out, security_level,
     );
 
diff --git a/host/commands/secure_env/secure_env_linux_main.cpp b/host/commands/secure_env/secure_env_linux_main.cpp
index ade41d3..1164ef2 100644
--- a/host/commands/secure_env/secure_env_linux_main.cpp
+++ b/host/commands/secure_env/secure_env_linux_main.cpp
@@ -26,6 +26,7 @@
 #include <tss2/tss2_rc.h>
 
 #include "common/libs/fs/shared_fd.h"
+#include "common/libs/security/channel_sharedfd.h"
 #include "common/libs/security/confui_sign.h"
 #include "common/libs/security/gatekeeper_channel_sharedfd.h"
 #include "common/libs/security/keymaster_channel_sharedfd.h"
@@ -38,9 +39,13 @@
 #include "host/commands/secure_env/in_process_tpm.h"
 #include "host/commands/secure_env/insecure_fallback_storage.h"
 #include "host/commands/secure_env/keymaster_responder.h"
+#include "host/commands/secure_env/oemlock/oemlock_responder.h"
+#include "host/commands/secure_env/oemlock/oemlock.h"
 #include "host/commands/secure_env/proxy_keymaster_context.h"
 #include "host/commands/secure_env/rust/kmr_ta.h"
 #include "host/commands/secure_env/soft_gatekeeper.h"
+#include "host/commands/secure_env/storage/insecure_json_storage.h"
+#include "host/commands/secure_env/storage/storage.h"
 #include "host/commands/secure_env/tpm_gatekeeper.h"
 #include "host/commands/secure_env/tpm_keymaster_context.h"
 #include "host/commands/secure_env/tpm_keymaster_enforcement.h"
@@ -50,8 +55,12 @@
 DEFINE_int32(confui_server_fd, -1, "A named socket to serve confirmation UI");
 DEFINE_int32(keymaster_fd_in, -1, "A pipe for keymaster communication");
 DEFINE_int32(keymaster_fd_out, -1, "A pipe for keymaster communication");
+DEFINE_int32(keymint_fd_in, -1, "A pipe for keymint communication");
+DEFINE_int32(keymint_fd_out, -1, "A pipe for keymint communication");
 DEFINE_int32(gatekeeper_fd_in, -1, "A pipe for gatekeeper communication");
 DEFINE_int32(gatekeeper_fd_out, -1, "A pipe for gatekeeper communication");
+DEFINE_int32(oemlock_fd_in, -1, "A pipe for oemlock communication");
+DEFINE_int32(oemlock_fd_out, -1, "A pipe for oemlock communication");
 DEFINE_int32(kernel_events_fd, -1,
              "A pipe for monitoring events based on "
              "messages written to the kernel log. This "
@@ -62,12 +71,14 @@
               "The TPM implementation. \"in_memory\" or \"host_device\"");
 
 DEFINE_string(keymint_impl, "tpm",
-              "The KeyMint implementation. \"tpm\", \"software\", \"rust-tpm\" "
-              "or \"rust-software\"");
+              "The KeyMint implementation. \"tpm\" or \"software\"");
 
 DEFINE_string(gatekeeper_impl, "tpm",
               "The gatekeeper implementation. \"tpm\" or \"software\"");
 
+DEFINE_string(oemlock_impl, "software",
+              "The oemlock implementation. \"tpm\" or \"software\"");
+
 namespace cuttlefish {
 namespace {
 
@@ -140,8 +151,27 @@
   }
 }
 
+fruit::Component<secure_env::Storage, oemlock::OemLock> ChooseOemlockComponent() {
+  return fruit::createComponent()
+      .registerProvider([]() -> secure_env::Storage* {
+        if (FLAGS_oemlock_impl == "software") {
+          return new secure_env::InsecureJsonStorage("oemlock_insecure");
+        } else if (FLAGS_oemlock_impl == "tpm") {
+          LOG(FATAL) << "Oemlock doesn't support TPM implementation";
+          abort();
+        } else {
+          LOG(FATAL) << "Invalid oemlock implementation: "
+                     << FLAGS_oemlock_impl;
+          abort();
+        }
+      })
+      .registerProvider([](secure_env::Storage& storage) -> oemlock::OemLock* {
+        return new oemlock::OemLock(storage);
+      });;
+}
+
 fruit::Component<TpmResourceManager, gatekeeper::GateKeeper,
-                 keymaster::KeymasterEnforcement>
+                 secure_env::Storage, oemlock::OemLock, keymaster::KeymasterEnforcement>
 SecureEnvComponent() {
   return fruit::createComponent()
       .registerProvider([]() -> Tpm* {  // fruit will take ownership
@@ -188,7 +218,8 @@
                                  insecure_storage);
       })
       .registerProvider([]() { return new gatekeeper::SoftGateKeeper(); })
-      .install(ChooseGatekeeperComponent);
+      .install(ChooseGatekeeperComponent)
+      .install(ChooseOemlockComponent);
 }
 
 }  // namespace
@@ -199,10 +230,11 @@
   keymaster::SoftKeymasterLogger km_logger;
 
   fruit::Injector<TpmResourceManager, gatekeeper::GateKeeper,
-                  keymaster::KeymasterEnforcement>
+                  secure_env::Storage, oemlock::OemLock, keymaster::KeymasterEnforcement>
       injector(SecureEnvComponent);
   TpmResourceManager* resource_manager = injector.get<TpmResourceManager*>();
   gatekeeper::GateKeeper* gatekeeper = injector.get<gatekeeper::GateKeeper*>();
+  oemlock::OemLock* oemlock = injector.get<oemlock::OemLock*>();
   keymaster::KeymasterEnforcement* keymaster_enforcement =
       injector.get<keymaster::KeymasterEnforcement*>();
   std::unique_ptr<keymaster::KeymasterContext> keymaster_context;
@@ -210,62 +242,68 @@
 
   std::vector<std::thread> threads;
 
-  if (android::base::StartsWith(FLAGS_keymint_impl, "rust-")) {
-    // Use the Rust reference implementation of KeyMint.
-    LOG(DEBUG) << "starting Rust KeyMint implementation";
-    int security_level;
-    if (FLAGS_keymint_impl == "rust-software") {
-      security_level = KM_SECURITY_LEVEL_SOFTWARE;
-    } else if (FLAGS_keymint_impl == "rust-tpm") {
-      security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
-    } else {
-      LOG(FATAL) << "Unknown keymaster implementation " << FLAGS_keymint_impl;
-      return -1;
-    }
-
-    int keymaster_in = FLAGS_keymaster_fd_in;
-    int keymaster_out = FLAGS_keymaster_fd_out;
-    TpmResourceManager* rm = resource_manager;
-    threads.emplace_back([rm, keymaster_in, keymaster_out, security_level]() {
-      kmr_ta_main(keymaster_in, keymaster_out, security_level, rm);
-    });
-
+  int security_level;
+  if (FLAGS_keymint_impl == "software") {
+    security_level = KM_SECURITY_LEVEL_SOFTWARE;
+  } else if (FLAGS_keymint_impl == "tpm") {
+    security_level = KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT;
   } else {
-    // Use the C++ reference implementation of KeyMint.
-    LOG(DEBUG) << "starting C++ KeyMint implementation";
-    if (FLAGS_keymint_impl == "software") {
-      // TODO: See if this is the right KM version.
-      keymaster_context.reset(new keymaster::PureSoftKeymasterContext(
-          keymaster::KmVersion::KEYMINT_3, KM_SECURITY_LEVEL_SOFTWARE));
-    } else if (FLAGS_keymint_impl == "tpm") {
-      keymaster_context.reset(
-          new TpmKeymasterContext(*resource_manager, *keymaster_enforcement));
-    } else {
-      LOG(FATAL) << "Unknown keymaster implementation " << FLAGS_keymint_impl;
-      return -1;
-    }
-    // keymaster::AndroidKeymaster puts the context pointer into a UniquePtr,
-    // taking ownership.
-    keymaster.reset(new keymaster::AndroidKeymaster(
-        new ProxyKeymasterContext(*keymaster_context), kOperationTableSize,
-        keymaster::MessageVersion(keymaster::KmVersion::KEYMINT_3,
-                                  0 /* km_date */)));
-
-    auto keymaster_in = DupFdFlag(FLAGS_keymaster_fd_in);
-    auto keymaster_out = DupFdFlag(FLAGS_keymaster_fd_out);
-    keymaster::AndroidKeymaster* borrowed_km = keymaster.get();
-    threads.emplace_back([keymaster_in, keymaster_out, borrowed_km]() {
-      while (true) {
-        SharedFdKeymasterChannel keymaster_channel(keymaster_in, keymaster_out);
-
-        KeymasterResponder keymaster_responder(keymaster_channel, *borrowed_km);
-
-        while (keymaster_responder.ProcessMessage()) {
-        }
-      }
-    });
+    LOG(FATAL) << "Unknown keymint implementation " << FLAGS_keymint_impl;
+    return -1;
   }
 
+  // The guest image may have either the C++ implementation of
+  // KeyMint/Keymaster, xor the Rust implementation of KeyMint.  Those different
+  // implementations each need to have a matching TA implementation in
+  // secure_env, but they use distincts ports (/dev/hvc3 for C++, /dev/hvc11 for
+  // Rust) so start threads for *both* TA implementations -- only one of them
+  // will receive any traffic from the guest.
+
+  // Start the Rust reference implementation of KeyMint.
+  LOG(INFO) << "starting Rust KeyMint TA implementation in a thread";
+
+  int keymint_in = FLAGS_keymint_fd_in;
+  int keymint_out = FLAGS_keymint_fd_out;
+  TpmResourceManager* rm = resource_manager;
+  threads.emplace_back([rm, keymint_in, keymint_out, security_level]() {
+    kmr_ta_main(keymint_in, keymint_out, security_level, rm);
+  });
+
+  // Start the C++ reference implementation of KeyMint.
+  LOG(INFO) << "starting C++ KeyMint implementation in a thread with FDs in="
+            << FLAGS_keymaster_fd_in << ", out=" << FLAGS_keymaster_fd_out;
+  if (security_level == KM_SECURITY_LEVEL_SOFTWARE) {
+    keymaster_context.reset(new keymaster::PureSoftKeymasterContext(
+        keymaster::KmVersion::KEYMINT_3, KM_SECURITY_LEVEL_SOFTWARE));
+  } else if (security_level == KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT) {
+    keymaster_context.reset(
+        new TpmKeymasterContext(*resource_manager, *keymaster_enforcement));
+  } else {
+    LOG(FATAL) << "Unknown keymaster security level " << security_level
+               << " for " << FLAGS_keymint_impl;
+    return -1;
+  }
+  // keymaster::AndroidKeymaster puts the context pointer into a UniquePtr,
+  // taking ownership.
+  keymaster.reset(new keymaster::AndroidKeymaster(
+      new ProxyKeymasterContext(*keymaster_context), kOperationTableSize,
+      keymaster::MessageVersion(keymaster::KmVersion::KEYMINT_3,
+                                0 /* km_date */)));
+
+  auto keymaster_in = DupFdFlag(FLAGS_keymaster_fd_in);
+  auto keymaster_out = DupFdFlag(FLAGS_keymaster_fd_out);
+  keymaster::AndroidKeymaster* borrowed_km = keymaster.get();
+  threads.emplace_back([keymaster_in, keymaster_out, borrowed_km]() {
+    while (true) {
+      SharedFdKeymasterChannel keymaster_channel(keymaster_in, keymaster_out);
+
+      KeymasterResponder keymaster_responder(keymaster_channel, *borrowed_km);
+
+      while (keymaster_responder.ProcessMessage()) {
+      }
+    }
+  });
+
   auto gatekeeper_in = DupFdFlag(FLAGS_gatekeeper_fd_in);
   auto gatekeeper_out = DupFdFlag(FLAGS_gatekeeper_fd_out);
   threads.emplace_back([gatekeeper_in, gatekeeper_out, &gatekeeper]() {
@@ -280,6 +318,17 @@
     }
   });
 
+  auto oemlock_in = DupFdFlag(FLAGS_oemlock_fd_in);
+  auto oemlock_out = DupFdFlag(FLAGS_oemlock_fd_out);
+  threads.emplace_back([oemlock_in, oemlock_out, &oemlock]() {
+    while (true) {
+      secure_env::SharedFdChannel channel(oemlock_in, oemlock_out);
+      oemlock::OemLockResponder responder(channel, *oemlock);
+      while (responder.ProcessMessage().ok()) {
+      }
+    }
+  });
+
   auto confui_server_fd = DupFdFlag(FLAGS_confui_server_fd);
   threads.emplace_back([confui_server_fd, resource_manager]() {
     ConfUiSignServer confui_sign_server(*resource_manager, confui_server_fd);
diff --git a/host/commands/secure_env/soft_oemlock.h b/host/commands/secure_env/soft_oemlock.h
new file mode 100644
index 0000000..b731ee9
--- /dev/null
+++ b/host/commands/secure_env/soft_oemlock.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2023 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.
+ *
+ */
+
+#pragma once
+
+#include <fruit/fruit.h>
+
+#include "host/commands/secure_env/oemlock.h"
+
+namespace cuttlefish {
+namespace oemlock {
+
+class SoftOemLock : public OemLock {
+ public:
+  INJECT(SoftOemLock()) : is_allowed_by_carrier_(true), is_allowed_by_device_(false) {}
+
+  bool IsOemUnlockAllowedByCarrier() const override {
+    return is_allowed_by_carrier_;
+  }
+
+  bool IsOemUnlockAllowedByDevice() const override {
+    return is_allowed_by_device_;
+  }
+
+  void SetOemUnlockAllowedByCarrier(bool allowed) override {
+    is_allowed_by_carrier_ = allowed;
+  }
+
+  void SetOemUnlockAllowedByDevice(bool allowed) override {
+    is_allowed_by_device_ = allowed;
+  }
+
+ private:
+  bool is_allowed_by_carrier_;
+  bool is_allowed_by_device_;
+};
+
+} // namespace oemlock
+} // namespace cuttlefish
\ No newline at end of file
diff --git a/host/commands/secure_env/storage/insecure_json_storage.cpp b/host/commands/secure_env/storage/insecure_json_storage.cpp
new file mode 100644
index 0000000..a85e7e4
--- /dev/null
+++ b/host/commands/secure_env/storage/insecure_json_storage.cpp
@@ -0,0 +1,88 @@
+//
+// Copyright (C) 2023 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.
+
+#include "host/commands/secure_env/storage/insecure_json_storage.h"
+
+#include <fstream>
+
+#include <android-base/file.h>
+#include <json/json.h>
+
+#include "common/libs/utils/base64.h"
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/json.h"
+
+namespace cuttlefish {
+namespace secure_env {
+namespace {
+
+Result<Json::Value> ReadJson(const std::string& path) {
+  std::string json;
+  CF_EXPECT(android::base::ReadFileToString(path, &json));
+  return CF_EXPECT(ParseJson(json));
+}
+
+Result<void> WriteJson(const std::string& path, const Json::Value& root) {
+  Json::StreamWriterBuilder builder;
+  auto json = Json::writeString(builder, root);
+  CF_EXPECT(android::base::WriteStringToFile(json, path));
+  return {};
+}
+
+} // namespace
+
+InsecureJsonStorage::InsecureJsonStorage(std::string path) : path_(std::move(path)) {}
+
+bool InsecureJsonStorage::Exists() const {
+  return ReadJson(path_).ok();
+}
+
+Result<bool> InsecureJsonStorage::HasKey(const std::string& key) const {
+  if (!FileHasContent(path_)) {
+    return false;
+  }
+  return CF_EXPECT(ReadJson(path_)).isMember(key);
+}
+
+Result<ManagedStorageData> InsecureJsonStorage::Read(const std::string& key) const {
+  auto root = CF_EXPECT(ReadJson(path_));
+  CF_EXPECT(root.isMember(key), "Key: " << key << " not found in " << path_);
+
+  std::vector<uint8_t> base64_buffer;
+  CF_EXPECT(DecodeBase64(root[key].asString(), &base64_buffer),
+            "Failed to decode base64 to read key: " << key);
+  auto storage_data = CF_EXPECT(CreateStorageData(base64_buffer.size()));
+  std::memcpy(storage_data->payload, reinterpret_cast<unsigned char *>(base64_buffer.data()),
+              base64_buffer.size());
+  return storage_data;
+}
+
+Result<void> InsecureJsonStorage::Write(const std::string& key, const StorageData& data) {
+  Json::Value root;
+  if (FileHasContent(path_)) {
+    root = CF_EXPECT(ReadJson(path_));
+  }
+
+  std::string value_base64;
+  CF_EXPECT(EncodeBase64(data.payload, data.size, &value_base64),
+            "Failed to encode base64 to write key: " << key);
+  root[key] = value_base64;
+
+  CF_EXPECT(WriteJson(path_, root));
+  return {};
+}
+
+}  // namespace oemlock
+}  // namespace cuttlefish
diff --git a/host/commands/secure_env/storage/insecure_json_storage.h b/host/commands/secure_env/storage/insecure_json_storage.h
new file mode 100644
index 0000000..f811774
--- /dev/null
+++ b/host/commands/secure_env/storage/insecure_json_storage.h
@@ -0,0 +1,37 @@
+//
+// Copyright (C) 2023 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.
+
+#pragma once
+
+#include "host/commands/secure_env/storage/storage.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+class InsecureJsonStorage : public secure_env::Storage {
+ public:
+  InsecureJsonStorage(std::string path);
+
+  Result<bool> HasKey(const std::string& key) const override;
+  Result<ManagedStorageData> Read(const std::string& key) const override;
+  Result<void> Write(const std::string& key, const StorageData& data) override;
+  bool Exists() const override;
+
+ private:
+  std::string path_;
+};
+
+}  // namespace secure_env
+}  // namespace cuttlefish
diff --git a/host/commands/secure_env/storage/storage.cpp b/host/commands/secure_env/storage/storage.cpp
new file mode 100644
index 0000000..5c7cb2f
--- /dev/null
+++ b/host/commands/secure_env/storage/storage.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#include "host/commands/secure_env/storage/storage.h"
+
+#include "keymaster/android_keymaster_utils.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+void StorageDataDestroyer::operator()(StorageData* ptr) {
+  {
+    keymaster::Eraser(ptr, sizeof(StorageData) + ptr->size);
+  }
+  std::free(ptr);
+}
+
+Result<ManagedStorageData> CreateStorageData(size_t size) {
+  const auto bytes_to_allocate = sizeof(StorageData) + size;
+  auto memory = std::malloc(bytes_to_allocate);
+  CF_EXPECT(memory != nullptr,
+            "Cannot allocate " << bytes_to_allocate << " bytes for storage data");
+  auto data = reinterpret_cast<StorageData*>(memory);
+  data->size = size;
+  return ManagedStorageData(data);
+}
+
+Result<ManagedStorageData> CreateStorageData(const void* data, size_t size) {
+  auto managed_data = CF_EXPECT(CreateStorageData(size));
+  std::memcpy(managed_data->payload, data, size);
+  return managed_data;
+}
+
+}  // namespace secure_env
+}  // namespace cuttlefish
diff --git a/host/commands/secure_env/storage/storage.h b/host/commands/secure_env/storage/storage.h
new file mode 100644
index 0000000..6815c34
--- /dev/null
+++ b/host/commands/secure_env/storage/storage.h
@@ -0,0 +1,69 @@
+//
+// Copyright (C) 2023 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.
+
+#pragma once
+
+#include <any>
+#include <string>
+
+#include "common/libs/utils/result.h"
+
+namespace cuttlefish {
+namespace secure_env {
+
+struct StorageData {
+  uint32_t size;
+  uint8_t payload[0];
+
+  Result<uint8_t> asUint8() {
+    CF_EXPECT(size == sizeof(uint8_t), "Size of payload is not matched with uint8 size");
+    return *reinterpret_cast<uint8_t*>(payload);
+  }
+};
+
+/**
+ * A destroyer for StorageData instances created with
+ * CreateStorageData. Wipes memory from the StorageData instances.
+ */
+class StorageDataDestroyer {
+ public:
+  void operator()(StorageData* ptr);
+};
+
+/** An owning pointer for a StorageData instance. */
+using ManagedStorageData = std::unique_ptr<StorageData, StorageDataDestroyer>;
+
+/**
+ * Allocates memory for a StorageData carrying a message of size
+ * `size`.
+ */
+Result<ManagedStorageData> CreateStorageData(size_t size);
+Result<ManagedStorageData> CreateStorageData(const void* data, size_t size);
+
+/**
+ * Storage abstraction to store binary blobs associated with string key
+*/
+class Storage {
+ public:
+  virtual Result<bool> HasKey(const std::string& key) const = 0;
+  virtual Result<ManagedStorageData> Read(const std::string& key) const = 0;
+  virtual Result<void> Write(const std::string& key, const StorageData& data) = 0;
+  virtual bool Exists() const = 0;
+
+  virtual ~Storage() = default;
+};
+
+} // namespace secure_env
+} // namespace cuttlefish
diff --git a/host/libs/config/config_flag.cpp b/host/libs/config/config_flag.cpp
index d4d5157..63afd23 100644
--- a/host/libs/config/config_flag.cpp
+++ b/host/libs/config/config_flag.cpp
@@ -16,6 +16,7 @@
 
 #include "host/libs/config/config_flag.h"
 
+#include <android-base/file.h>
 #include <android-base/logging.h>
 #include <android-base/strings.h>
 #include <gflags/gflags.h>
@@ -34,6 +35,8 @@
 DEFINE_string(system_image_dir, CF_DEFAULTS_SYSTEM_IMAGE_DIR, "");
 
 using gflags::FlagSettingMode::SET_FLAGS_DEFAULT;
+using android::base::ReadFileToString;
+using android::base::Split;
 
 namespace cuttlefish {
 
@@ -192,22 +195,36 @@
     if (!FileExists(info_path)) {
       return {};
     }
-    std::ifstream ifs{info_path};
-    if (!ifs.is_open()) {
-      return {};
-    }
     std::string android_info;
-    ifs >> android_info;
-    std::string_view local_android_info(android_info);
-    if (!android::base::ConsumePrefix(&local_android_info, "config=")) {
+    if(!ReadFileToString(info_path, &android_info)) {
       return {};
     }
-    if (!config_reader_.HasConfig(std::string{local_android_info})) {
+    // grab the last value of config in android-info.txt,
+    // it's the setting that's respected.
+    // TODO (rammuthiah) Replace this logic with ParseMiscInfo
+    // from host/commands/assemble_cvd/misc_info.h
+    // Currently blocked on linking error for misc_info which is part of
+    // assemble_cvd and this bit of code which is in run_cvd.
+    size_t config_idx = android_info.rfind("config=");
+    if (config_idx == std::string::npos) {
+      return {};
+    }
+    std::string config_value = android_info.substr(config_idx);
+    std::string_view local_config_value(config_value);
+    if (!android::base::ConsumePrefix(&local_config_value, "config=")) {
+      return {};
+    }
+    auto split_config = Split(std::string{local_config_value},"\n");
+    if (split_config.empty()) {
+      return {};
+    }
+    config_value = split_config[0];
+    if (!config_reader_.HasConfig(config_value)) {
       LOG(WARNING) << info_path << " contains invalid config preset: '"
-                   << local_android_info << "'.";
+                   << config_value << "'.";
       return {};
     }
-    return std::string{local_android_info};
+    return config_value;
   }
 
   ConfigReader& config_reader_;
diff --git a/host/libs/config/cuttlefish_config.cpp b/host/libs/config/cuttlefish_config.cpp
index 1b9e07b..5c9e8dc 100644
--- a/host/libs/config/cuttlefish_config.cpp
+++ b/host/libs/config/cuttlefish_config.cpp
@@ -149,6 +149,8 @@
     return SecureHal::Keymint;
   } else if (mode == "gatekeeper") {
     return SecureHal::Gatekeeper;
+  } else if (mode == "oemlock") {
+    return SecureHal::Oemlock;
   } else {
     return SecureHal::Unknown;
   }
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 16151b3..9a2af86 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -71,6 +71,7 @@
   Unknown,
   Keymint,
   Gatekeeper,
+  Oemlock,
 };
 
 // Holds the configuration of the cuttlefish instances.
diff --git a/host/libs/config/data_image.cpp b/host/libs/config/data_image.cpp
index 45dbad8..e3a6fe4 100644
--- a/host/libs/config/data_image.cpp
+++ b/host/libs/config/data_image.cpp
@@ -307,16 +307,13 @@
  private:
   std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
   bool Setup() override {
-    bool misc_exists = FileHasContent(instance_.misc_image());
-
-    if (misc_exists) {
-      LOG(DEBUG) << "misc partition image: use existing at \""
-                 << instance_.misc_image() << "\"";
+    if (FileHasContent(instance_.new_misc_image())) {
+      LOG(DEBUG) << "misc partition image already exists";
       return true;
     }
 
     LOG(DEBUG) << "misc partition image: creating empty at \""
-               << instance_.misc_image() << "\"";
+               << instance_.new_misc_image() << "\"";
     if (!CreateBlankImage(instance_.new_misc_image(), 1 /* mb */, "none")) {
       LOG(ERROR) << "Failed to create misc image";
       return false;
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index bfa1c98..100b71e 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -316,6 +316,7 @@
     crosvm_cmd.Cmd().AddParameter("--cid=", instance.vsock_guest_cid());
   }
 
+  // /dev/hvc0 = kernel console
   // If kernel log is enabled, the virtio-console port will be specified as
   // a true console for Linux, and kernel messages will be printed there.
   // Otherwise, the port will still be set up for bootloader and userspace
@@ -326,6 +327,7 @@
   crosvm_cmd.AddHvcReadOnly(instance.kernel_log_pipe_name(),
                             instance.enable_kernel_log());
 
+  // /dev/hvc1 = serial console
   if (instance.console()) {
     // stdin is the only currently supported way to write data to a serial port
     // in crosvm. A file (named pipe) is used here instead of stdout to ensure
@@ -383,16 +385,20 @@
     return StopperResult::kStopSuccess;
   });
 
+  // /dev/hvc2 = serial logging
   // Serial port for logcat, redirected to a pipe
   crosvm_cmd.AddHvcReadOnly(instance.logcat_pipe_name());
 
+  // /dev/hvc3 = keymaster (C++ implementation)
   crosvm_cmd.AddHvcReadWrite(
       instance.PerInstanceInternalPath("keymaster_fifo_vm.out"),
       instance.PerInstanceInternalPath("keymaster_fifo_vm.in"));
+  // /dev/hvc4 = gatekeeper
   crosvm_cmd.AddHvcReadWrite(
       instance.PerInstanceInternalPath("gatekeeper_fifo_vm.out"),
       instance.PerInstanceInternalPath("gatekeeper_fifo_vm.in"));
 
+  // /dev/hvc5 = bt
   if (config.enable_host_bluetooth()) {
     crosvm_cmd.AddHvcReadWrite(
         instance.PerInstanceInternalPath("bt_fifo_vm.out"),
@@ -400,6 +406,9 @@
   } else {
     crosvm_cmd.AddHvcSink();
   }
+
+  // /dev/hvc6 = gnss
+  // /dev/hvc7 = location
   if (instance.enable_gnss_grpc_proxy()) {
     crosvm_cmd.AddHvcReadWrite(
         instance.PerInstanceInternalPath("gnsshvc_fifo_vm.out"),
@@ -413,10 +422,12 @@
     }
   }
 
+  // /dev/hvc8 = confirmationui
   crosvm_cmd.AddHvcReadWrite(
       instance.PerInstanceInternalPath("confui_fifo_vm.out"),
       instance.PerInstanceInternalPath("confui_fifo_vm.in"));
 
+  // /dev/hvc9 = uwb
   if (config.enable_host_uwb()) {
     crosvm_cmd.AddHvcReadWrite(
         instance.PerInstanceInternalPath("uwb_fifo_vm.out"),
@@ -425,6 +436,16 @@
     crosvm_cmd.AddHvcSink();
   }
 
+  // /dev/hvc10 = oemlock
+  crosvm_cmd.AddHvcReadWrite(
+      instance.PerInstanceInternalPath("oemlock_fifo_vm.out"),
+      instance.PerInstanceInternalPath("oemlock_fifo_vm.in"));
+
+  // /dev/hvc11 = keymint (Rust implementation)
+  crosvm_cmd.AddHvcReadWrite(
+      instance.PerInstanceInternalPath("keymint_fifo_vm.out"),
+      instance.PerInstanceInternalPath("keymint_fifo_vm.in"));
+
   for (auto i = 0; i < VmManager::kMaxDisks - disk_num; i++) {
     crosvm_cmd.AddHvcSink();
   }
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index 27a3ddf..a2744a3 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -457,6 +457,7 @@
     }
   }
 
+  // /dev/hvc0 = kernel console
   // If kernel log is enabled, the virtio-console port will be specified as
   // a true console for Linux, and kernel messages will be printed there.
   // Otherwise, the port will still be set up for bootloader and userspace
@@ -469,6 +470,7 @@
   //  actually managed by the kernel as a console is handled elsewhere.)
   add_hvc_ro(instance.kernel_log_pipe_name());
 
+  // /dev/hvc1 = serial console
   if (instance.console()) {
     if (instance.kgdb() || instance.use_bootloader()) {
       add_serial_console(instance.console_pipe_prefix());
@@ -495,17 +497,23 @@
     add_hvc_sink();
   }
 
+  // /dev/hvc2 = serial logging
   // Serial port for logcat, redirected to a pipe
   add_hvc_ro(instance.logcat_pipe_name());
 
+  // /dev/hvc3 = keymaster (C++ implementation)
   add_hvc(instance.PerInstanceInternalPath("keymaster_fifo_vm"));
+  // /dev/hvc4 = gatekeeper
   add_hvc(instance.PerInstanceInternalPath("gatekeeper_fifo_vm"));
+  // /dev/hvc5 = bt
   if (config.enable_host_bluetooth()) {
     add_hvc(instance.PerInstanceInternalPath("bt_fifo_vm"));
   } else {
     add_hvc_sink();
   }
 
+  // /dev/hvc6 = gnss
+  // /dev/hvc7 = location
   if (instance.enable_gnss_grpc_proxy()) {
     add_hvc(instance.PerInstanceInternalPath("gnsshvc_fifo_vm"));
     add_hvc(instance.PerInstanceInternalPath("locationhvc_fifo_vm"));
@@ -526,14 +534,22 @@
    * confui_fifo_vm.{in/out} are created along with the streamer process,
    * which is not created w/ QEMU.
    */
+  // /dev/hvc8 = confirmationui
   add_hvc_sink();
 
+  // /dev/hvc9 = uwb
   if (config.enable_host_uwb()) {
     add_hvc("uwb_fifo_vm");
   } else {
     add_hvc_sink();
   }
 
+  // /dev/hvc10 = oemlock
+  add_hvc(instance.PerInstanceInternalPath("oemlock_fifo_vm"));
+
+  // /dev/hvc11 = keymint (Rust implementation)
+  add_hvc(instance.PerInstanceInternalPath("keymint_fifo_vm"));
+
   auto disk_num = instance.virtual_disk_paths().size();
 
   for (auto i = 0; i < VmManager::kMaxDisks - disk_num; i++) {
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 739e0db..4b116bf 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -41,8 +41,20 @@
   // so even if they are disabled and the guest isn't using them, they don't
   // need to consume host resources, except for the PCI ID. Use this trick to
   // keep the number of PCI IDs assigned constant for all flags/vm manager
-  // combinations
-  static const int kDefaultNumHvcs = 10;
+  // combinations.
+  // - /dev/hvc0 = kernel console
+  // - /dev/hvc1 = serial console
+  // - /dev/hvc2 = serial logging
+  // - /dev/hvc3 = keymaster
+  // - /dev/hvc4 = gatekeeper
+  // - /dev/hvc5 = bt
+  // - /dev/hvc6 = gnss
+  // - /dev/hvc7 = location
+  // - /dev/hvc8 = confirmationui
+  // - /dev/hvc9 = uwb
+  // - /dev/hvc10 = oemlock
+  // - /dev/hvc11 = keymint
+  static const int kDefaultNumHvcs = 12;
 
   // This is the number of virtual disks (block devices) that should be
   // configured by the VmManager. Related to the description above regarding
diff --git a/shared/auto/android-info.txt b/shared/auto/android-info.txt
index cc15c01..74c0e2e 100644
--- a/shared/auto/android-info.txt
+++ b/shared/auto/android-info.txt
@@ -1 +1,2 @@
 config=auto
+gfxstream=supported
diff --git a/shared/auto_md/android-info.txt b/shared/auto_md/android-info.txt
index ac7c0e7..1a130ff 100644
--- a/shared/auto_md/android-info.txt
+++ b/shared/auto_md/android-info.txt
@@ -1 +1,2 @@
 config=auto_md
+gfxstream=supported
diff --git a/shared/auto_portrait/android-info.txt b/shared/auto_portrait/android-info.txt
index 60b759e..ea15130 100644
--- a/shared/auto_portrait/android-info.txt
+++ b/shared/auto_portrait/android-info.txt
@@ -1 +1,2 @@
 config=auto_portrait
+gfxstream=supported
diff --git a/shared/config/ueventd.rc b/shared/config/ueventd.rc
index 4e80bda..c604e3d 100644
--- a/shared/config/ueventd.rc
+++ b/shared/config/ueventd.rc
@@ -15,7 +15,7 @@
 # seriallogging
 /dev/hvc2 0660 system logd
 
-# keymaster
+# keymaster / C++
 /dev/hvc3 0666 system system
 
 # gatekeeper
@@ -38,5 +38,11 @@
 # uwb
 /dev/hvc9 0660 uwb uwb
 
+# oemlock
+/dev/hvc10 0660 hsm hsm
+
+# keymint / Rust
+/dev/hvc11 0666 system system
+
 # Factory Reset Protection
 /dev/block/by-name/frp 0660 system system
diff --git a/shared/device.mk b/shared/device.mk
index d860dda..59338ed 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -304,13 +304,6 @@
 	android.hardware.ir-service.example \
 	consumerir.default
 
-
-#
-# OemLock aidl HAL
-#
-PRODUCT_PACKAGES += \
-    android.hardware.oemlock-service.example
-
 #
 # Authsecret AIDL HAL
 #
@@ -442,12 +435,23 @@
 # Gatekeeper
 #
 ifeq ($(LOCAL_GATEKEEPER_PRODUCT_PACKAGE),)
-       LOCAL_GATEKEEPER_PRODUCT_PACKAGE := android.hardware.gatekeeper-service.remote
+    LOCAL_GATEKEEPER_PRODUCT_PACKAGE := android.hardware.gatekeeper-service.remote
 endif
 PRODUCT_PACKAGES += \
     $(LOCAL_GATEKEEPER_PRODUCT_PACKAGE)
 
 #
+# Oemlock
+#
+ifeq ($(LOCAL_OEMLOCK_PRODUCT_PACKAGE),)
+    LOCAL_OEMLOCK_PRODUCT_PACKAGE := android.hardware.oemlock-service.remote
+endif
+PRODUCT_PACKAGES += \
+    $(LOCAL_OEMLOCK_PRODUCT_PACKAGE)
+
+PRODUCT_VENDOR_PROPERTIES += ro.oem_unlock_supported=1
+
+#
 # GPS
 #
 LOCAL_GNSS_PRODUCT_PACKAGE ?= \
@@ -505,12 +509,6 @@
     LOCAL_KEYMINT_PRODUCT_PACKAGE := android.hardware.security.keymint-service.rust
 endif
 
-ifeq ($(LOCAL_KEYMINT_PRODUCT_PACKAGE),android.hardware.security.keymint-service.rust)
-    # KeyMint HAL has been overridden to force use of the Rust reference implementation.
-    # Set the build config for secure_env to match.
-    $(call soong_config_set,secure_env,keymint_impl,rust)
-endif
-
 PRODUCT_PACKAGES += \
     $(LOCAL_KEYMINT_PRODUCT_PACKAGE) \
 
diff --git a/shared/foldable/android-info.txt b/shared/foldable/android-info.txt
index 8552685..53cfa11 100644
--- a/shared/foldable/android-info.txt
+++ b/shared/foldable/android-info.txt
@@ -1 +1,2 @@
 config=foldable
+gfxstream=supported
diff --git a/shared/go/android-info.txt b/shared/go/android-info.txt
index 68f4826..ae9578c 100644
--- a/shared/go/android-info.txt
+++ b/shared/go/android-info.txt
@@ -1 +1,2 @@
 config=go
+gfxstream=supported
diff --git a/shared/minidroid/android-info.txt b/shared/minidroid/android-info.txt
index fc79813..50453d6 100644
--- a/shared/minidroid/android-info.txt
+++ b/shared/minidroid/android-info.txt
@@ -1 +1,2 @@
 config=minidroid
+gfxstream=supported
diff --git a/shared/phone/android-info.txt b/shared/phone/android-info.txt
index 2286c3d..169f04d 100644
--- a/shared/phone/android-info.txt
+++ b/shared/phone/android-info.txt
@@ -1 +1,2 @@
 config=phone
+gfxstream=supported
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 0d94687..4805bb1 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -38,6 +38,12 @@
 # hvc9 for uwb
 /dev/hvc9  u:object_r:uwb_device:s0
 
+# hvc10 for oemlock
+/dev/hvc10  u:object_r:oemlock_device:s0
+
+# hvc11 for keymint / Rust
+/dev/hvc11  u:object_r:keymint_device:s0
+
 # ARM serial console device
 /dev/ttyAMA[0-9]*  u:object_r:serial_device:s0
 
@@ -94,11 +100,11 @@
 /vendor/bin/hw/android\.hardware\.thermal@2\.0-service\.mock  u:object_r:hal_thermal_default_exec:s0
 /vendor/bin/hw/android\.hardware\.identity-service\.remote  u:object_r:hal_identity_remote_exec:s0
 /vendor/bin/hw/android\.hardware\.security\.keymint-service\.remote  u:object_r:hal_keymint_remote_exec:s0
-/vendor/bin/hw/android\.hardware\.security\.keymint-service\.rust  u:object_r:hal_keymint_remote_exec:s0
+/vendor/bin/hw/android\.hardware\.security\.keymint-service\.rust  u:object_r:hal_keymint_rust_exec:s0
 /vendor/bin/hw/android\.hardware\.keymaster@4\.1-service.remote  u:object_r:hal_keymaster_remote_exec:s0
 /vendor/bin/hw/android\.hardware\.gatekeeper-service.remote  u:object_r:hal_gatekeeper_remote_exec:s0
 /vendor/bin/hw/android\.hardware\.confirmationui-service.cuttlefish  u:object_r:hal_confirmationui_cuttlefish_exec:s0
-/vendor/bin/hw/android\.hardware\.oemlock-service.example u:object_r:hal_oemlock_default_exec:s0
+/vendor/bin/hw/android\.hardware\.oemlock-service.remote  u:object_r:hal_oemlock_remote_exec:s0
 /vendor/bin/hw/android\.hardware\.weaver-service.example u:object_r:hal_weaver_default_exec:s0
 /vendor/bin/hw/android\.hardware\.authsecret@1\.0-service  u:object_r:hal_authsecret_default_exec:s0
 /vendor/bin/hw/android\.hardware\.authsecret-service.example u:object_r:hal_authsecret_default_exec:s0
diff --git a/shared/sepolicy/vendor/genfs_contexts b/shared/sepolicy/vendor/genfs_contexts
index 758fb54..ce10445 100644
--- a/shared/sepolicy/vendor/genfs_contexts
+++ b/shared/sepolicy/vendor/genfs_contexts
@@ -30,7 +30,7 @@
 dnl')dnl
 dnl
 # crosvm (x86)
-cf_pci_block_device(/devices/pci0000:00, 0xc, 11)
+cf_pci_block_device(/devices/pci0000:00, 0xe, 13)
 cf_pci_gpu_device(/devices/pci0000:00, 0x2)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/rtc_cmos/rtc u:object_r:sysfs_rtc:s0
@@ -69,6 +69,8 @@
 genfscon sysfs /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1c/wakeup u:object_r:sysfs_wakeup:s0
 genfscon sysfs /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1d/wakeup u:object_r:sysfs_wakeup:s0
 genfscon sysfs /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1e/wakeup u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:1f/wakeup u:object_r:sysfs_wakeup:s0
+genfscon sysfs /devices/LNXSYSTM:00/LNXSYBUS:00/PNP0A08:00/device:20/wakeup u:object_r:sysfs_wakeup:s0
 ## find /sys/devices/platform/* -type d -name 'wakeup[0-9]*'
 genfscon sysfs /devices/platform/rtc_cmos/rtc/rtc0/wakeup3 u:object_r:sysfs_wakeup:s0
 genfscon sysfs /devices/platform/rtc_cmos/rtc/rtc0/wakeup4 u:object_r:sysfs_wakeup:s0
@@ -82,7 +84,7 @@
 genfscon sysfs /devices/virtual/mac80211_hwsim/hwsim1/net u:object_r:sysfs_net:s0
 
 # crosvm (arm64)
-cf_pci_block_device(/devices/platform/10000.pci/pci0000:00, 0xd, 12)
+cf_pci_block_device(/devices/platform/10000.pci/pci0000:00, 0xf, 14)
 cf_pci_gpu_device(/devices/platform/10000.pci/pci0000:00, 0x2)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/2000.rtc/rtc u:object_r:sysfs_rtc:s0
@@ -90,7 +92,7 @@
 ## arm64 2000.rtc on crosvm does not currently expose a wakeup node
 
 # qemu (x86)
-cf_pci_block_device(/devices/pci0000:00, 0xd, 11)
+cf_pci_block_device(/devices/pci0000:00, 0xf, 13)
 #cf_pci_gpu_device(/devices/pci0000:00, 0x2) - duplicated with crosvm(x86)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/pnp0/00:04/rtc u:object_r:sysfs_rtc:s0
@@ -98,7 +100,7 @@
 cf_rtc_wakeup_alarmtimer(/devices/pnp0/00:04, 0, 19)
 
 # qemu (arm64)
-cf_pci_block_device(/devices/platform/4010000000.pcie/pci0000:00, 0xc, 11)
+cf_pci_block_device(/devices/platform/4010000000.pcie/pci0000:00, 0xe, 13)
 cf_pci_gpu_device(/devices/platform/4010000000.pcie/pci0000:00, 0x1)
 ## find /sys/devices/platform/* -type d -name 'rtc[0-9]' | sed 's,/rtc[0-9],,'
 genfscon sysfs /devices/platform/9010000.pl031/rtc u:object_r:sysfs_rtc:s0
@@ -106,13 +108,13 @@
 cf_rtc_wakeup_alarmtimer(/devices/platform/9010000.pl031, 0, 0)
 
 # qemu (arm)
-cf_pci_block_device(/devices/platform/3f000000.pcie/pci0000:00, 0xc, 11)
+cf_pci_block_device(/devices/platform/3f000000.pcie/pci0000:00, 0xe, 13)
 cf_pci_gpu_device(/devices/platform/3f000000.pcie/pci0000:00, 0x1)
 genfscon sysfs /devices/platform/rtc-test.1/wakeup/wakeup2 u:object_r:sysfs_wakeup:s0
 genfscon sysfs /devices/platform/rtc-test.2/wakeup/wakeup3 u:object_r:sysfs_wakeup:s0
 
 # qemu (riscv64)
-cf_pci_block_device(/devices/platform/soc/30000000.pci/pci0000:00, 0xd, 12)
+cf_pci_block_device(/devices/platform/soc/30000000.pci/pci0000:00, 0xf, 14)
 cf_pci_gpu_device(/devices/platform/soc/30000000.pci/pci0000:00, 0x1)
 
 # common on all platforms / vm managers
diff --git a/shared/sepolicy/vendor/hal_keymint_rust.te b/shared/sepolicy/vendor/hal_keymint_rust.te
new file mode 100644
index 0000000..f1adb4d
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_keymint_rust.te
@@ -0,0 +1,18 @@
+type hal_keymint_rust, domain;
+hal_server_domain(hal_keymint_rust, hal_keymint)
+
+type hal_keymint_rust_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_keymint_rust)
+
+type keymint_device, file_type;
+
+allow hal_keymint_rust device:dir r_dir_perms;
+allow hal_keymint_rust keymint_device:chr_file rw_file_perms;
+
+# Write to kernel log (/dev/kmsg)
+allow hal_keymint_rust kmsg_device:chr_file w_file_perms;
+allow hal_keymint_rust kmsg_device:chr_file getattr;
+
+get_prop(hal_keymint_rust, vendor_security_patch_level_prop)
+get_prop(hal_keymint_rust, vendor_boot_security_patch_level_prop)
+get_prop(hal_keymint_rust, serialno_prop)
diff --git a/shared/sepolicy/vendor/hal_oemlock_remote.te b/shared/sepolicy/vendor/hal_oemlock_remote.te
new file mode 100644
index 0000000..f775b6b
--- /dev/null
+++ b/shared/sepolicy/vendor/hal_oemlock_remote.te
@@ -0,0 +1,14 @@
+type hal_oemlock_remote, domain;
+hal_server_domain(hal_oemlock_remote, hal_oemlock)
+
+type hal_oemlock_remote_exec, exec_type, vendor_file_type, file_type;
+init_daemon_domain(hal_oemlock_remote)
+
+type oemlock_device, file_type;
+
+allow hal_oemlock_remote device:dir r_dir_perms;
+allow hal_oemlock_remote oemlock_device:chr_file rw_file_perms;
+
+# Write to kernel log (/dev/kmsg)
+allow hal_oemlock_remote kmsg_device:chr_file w_file_perms;
+allow hal_oemlock_remote kmsg_device:chr_file getattr;
diff --git a/shared/sepolicy/vendor/init.te b/shared/sepolicy/vendor/init.te
index 22a6758..c8002d0 100644
--- a/shared/sepolicy/vendor/init.te
+++ b/shared/sepolicy/vendor/init.te
@@ -31,5 +31,7 @@
 allow init confirmationui_device:chr_file rw_file_perms;
 allow init bt_device:chr_file rw_file_perms;
 allow init uwb_device:chr_file rw_file_perms;
+allow init oemlock_device:chr_file rw_file_perms;
+allow init keymint_device:chr_file rw_file_perms;
 
 allow init frp_block_device:blk_file setattr;
diff --git a/shared/sepolicy/vendor/ueventd.te b/shared/sepolicy/vendor/ueventd.te
index 6bea104..5376cee 100644
--- a/shared/sepolicy/vendor/ueventd.te
+++ b/shared/sepolicy/vendor/ueventd.te
@@ -4,3 +4,5 @@
 allow ueventd gatekeeper_device:chr_file { rw_file_perms create setattr };
 allow ueventd confirmationui_device:chr_file { rw_file_perms create setattr };
 allow ueventd metrics_helper_device:chr_file { rw_file_perms create setattr };
+allow ueventd oemlock_device:chr_file { rw_file_perms create setattr };
+allow ueventd keymint_device:chr_file { rw_file_perms create setattr };
diff --git a/shared/slim/android-info.txt b/shared/slim/android-info.txt
index b0bf39b..e7e5bf0 100644
--- a/shared/slim/android-info.txt
+++ b/shared/slim/android-info.txt
@@ -1 +1,2 @@
 config=slim
+gfxstream=supported
diff --git a/shared/tv/android-info.txt b/shared/tv/android-info.txt
index 8eae902..c438609 100644
--- a/shared/tv/android-info.txt
+++ b/shared/tv/android-info.txt
@@ -1 +1,2 @@
 config=tv
+gfxstream=supported
diff --git a/shared/wear/android-info.txt b/shared/wear/android-info.txt
index 22a5b5e..02e029b 100644
--- a/shared/wear/android-info.txt
+++ b/shared/wear/android-info.txt
@@ -1 +1,2 @@
 config=wear
+gfxstream=supported
diff --git a/tests/hal/hal_implementation_test.cpp b/tests/hal/hal_implementation_test.cpp
index 55926c6..eb2001c 100644
--- a/tests/hal/hal_implementation_test.cpp
+++ b/tests/hal/hal_implementation_test.cpp
@@ -98,7 +98,7 @@
     "android.hardware.memtrack@1.0",
     "android.hardware.neuralnetworks@1.3", // converted to AIDL, see b/161428342
     "android.hardware.nfc@1.2",
-    "android.hardware.oemlock@1.0",
+    "android.hardware.oemlock@1.0", // converted to AIDL, see b/176107318 b/282160400
     "android.hardware.power@1.3",
     "android.hardware.power.stats@1.0",
     "android.hardware.radio@1.6", // converted to AIDL
diff --git a/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java b/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java
index 50993da..9730c1a 100644
--- a/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java
+++ b/tests/powerwash/src/com/android/cuttlefish/tests/PowerwashTest.java
@@ -19,7 +19,6 @@
 
 import com.android.tradefed.config.Option;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.RemoteAndroidDevice;
 import com.android.tradefed.device.cloud.RemoteAndroidVirtualDevice;
 import com.android.tradefed.device.internal.DeviceResetHandler;
 import com.android.tradefed.log.LogUtil.CLog;
@@ -83,27 +82,13 @@
             CLog.d("Powerwash attempt #%d", i);
             long start = System.currentTimeMillis();
             boolean success = false;
-            if (getDevice() instanceof RemoteAndroidVirtualDevice) {
-                mCuttlefishHostUser = ((RemoteAndroidVirtualDevice) getDevice()).getInitialUser();
-                mCuttlefishDeviceNumOffset = ((RemoteAndroidVirtualDevice) getDevice())
-                        .getInitialDeviceNumOffset();
-                if (mCuttlefishDeviceNumOffset != null && mCuttlefishHostUser != null) {
-                    success = ((RemoteAndroidVirtualDevice) getDevice())
-                            .powerwashGce(mCuttlefishHostUser, mCuttlefishDeviceNumOffset)
-                            .getStatus().equals(CommandStatus.SUCCESS);
-                } else {
-                    success = ((RemoteAndroidVirtualDevice) getDevice())
-                            .powerwash().getStatus().equals(CommandStatus.SUCCESS);
-                }
-            } else {
-                // We don't usually expect tests to use our feature server, but in this case we are
-                // validating the feature itself so it's fine
-                DeviceResetHandler handler = new DeviceResetHandler(getInvocationContext());
-                try {
-                    success = handler.resetDevice(getDevice());
-                } catch (DeviceNotAvailableException e) {
-                    CLog.e(e);
-                }
+            // We don't usually expect tests to use our feature server, but in this case we are
+            // validating the feature itself so it's fine
+            DeviceResetHandler handler = new DeviceResetHandler(getInvocationContext());
+            try {
+                success = handler.resetDevice(getDevice());
+            } catch (DeviceNotAvailableException e) {
+                CLog.e(e);
             }
             assertTrue(String.format("Powerwash reset failed during attemt #%d", i), success);
             long duration = System.currentTimeMillis() - start;