[qcom][smc] Add qcom specific smc interface
Qualcomm's interpretation of the SMC calling conventions requires
keeping track of a request's session id returned from smc calls
in X6. This change moves support for Qualcomm's SMC retry mechanism
from PIL to a library including storage of session id across retires
to be used by other QSEE clients.
Test: PIL authentication of the Audio DSP FW image.
Change-Id: I762e4dbb0283960d90c2da590321b0f10168f4ca
diff --git a/zircon/system/dev/fw/qcom-pil/BUILD.gn b/zircon/system/dev/fw/qcom-pil/BUILD.gn
index 6ae72b9..0bbef09 100644
--- a/zircon/system/dev/fw/qcom-pil/BUILD.gn
+++ b/zircon/system/dev/fw/qcom-pil/BUILD.gn
@@ -12,6 +12,7 @@
deps = [
"$zx/system/banjo/ddk-protocol-platform-bus",
"$zx/system/banjo/ddk-protocol-platform-device",
+ "$zx/system/dev/lib/qcom",
"$zx/system/ulib/ddk",
"$zx/system/ulib/ddktl",
"$zx/system/ulib/elfload",
diff --git a/zircon/system/dev/fw/qcom-pil/qcom-pil.cpp b/zircon/system/dev/fw/qcom-pil/qcom-pil.cpp
index b1d22d2..7358935 100644
--- a/zircon/system/dev/fw/qcom-pil/qcom-pil.cpp
+++ b/zircon/system/dev/fw/qcom-pil/qcom-pil.cpp
@@ -13,6 +13,7 @@
#include <fbl/alloc_checker.h>
#include <fbl/string_buffer.h>
#include <fbl/unique_ptr.h>
+#include <qcom/smc.h>
#include "qcom-pil.h"
@@ -65,8 +66,8 @@
CreateSmcArgs(2, SmcArgType::kValue, SmcArgType::kBufferReadWrite),
fw_[fw_n].id, // kValue.
fw_[fw_n].pa); // kBufferReadWrite.
- status = SmcCall(¶ms, &result);
- if (status != ZX_OK || result.arg0 != kSmcOk) {
+ status = qcom::SmcCall(smc_.get(), ¶ms, &result);
+ if (status != ZX_OK || result.arg0 != qcom::kSmcOk) {
zxlogf(ERROR, "%s metadata init failed %d/%d\n", __func__, status,
static_cast<int>(result.arg0));
return status;
@@ -110,8 +111,8 @@
fw_[fw_n].id, // kValue.
fw_[fw_n].pa, // kValue, not clear why not a kBuffer...
total_size); // kValue.
- status = SmcCall(¶ms, &result);
- if (status != ZX_OK || result.arg0 != kSmcOk) {
+ status = qcom::SmcCall(smc_.get(), ¶ms, &result);
+ if (status != ZX_OK || result.arg0 != qcom::kSmcOk) {
zxlogf(ERROR, "%s memory setup failed %d/%d\n", __func__, status,
static_cast<int>(result.arg0));
return status;
@@ -151,8 +152,8 @@
// Authenticates the whole image via SMC call.
params = CreatePilSmcParams(PilCmd::AuthAndReset, CreateSmcArgs(1, SmcArgType::kValue),
fw_[fw_n].id);
- status = SmcCall(¶ms, &result);
- if (status != ZX_OK || result.arg0 != kSmcOk) {
+ status = qcom::SmcCall(smc_.get(), ¶ms, &result);
+ if (status != ZX_OK || result.arg0 != qcom::kSmcOk) {
zxlogf(ERROR, "%s authentication failed %d/%d\n", __func__, status,
static_cast<int>(result.arg0));
return status;
@@ -168,36 +169,6 @@
return 0;
}
-zx_status_t PilDevice::SmcCall(zx_smc_parameters_t* params, zx_smc_result_t* result) {
- zxlogf(TRACE, "SMC params 0x%X 0x%lX 0x%lX 0x%lX 0x%lX 0x%lX\n", params->func_id,
- params->arg1, params->arg2, params->arg3, params->arg4, params->arg5);
- auto status = zx_smc_call(smc_.get(), params, result);
- zxlogf(TRACE, "SMC results %ld 0x%lX 0x%lX 0x%lX\n", result->arg0, result->arg1, result->arg2,
- result->arg3);
-
- constexpr int total_retry_msecs = 2000;
- constexpr int busy_retry_msecs = 30;
- constexpr int busy_retries = total_retry_msecs / busy_retry_msecs;
- int busy_retry = busy_retries;
- while (status == ZX_OK && // Wait forever for smc_interrupted, limited for smc_busy replies.
- (result->arg0 == kSmcInterrupted || (result->arg0 == kSmcBusy && busy_retry--))) {
- if (result->arg0 == kSmcBusy) {
- zx_nanosleep(zx_deadline_after(ZX_MSEC(busy_retry_msecs)));
- }
- params->arg6 = result->arg6; // Pass optional session_id received via x6 back in any retry.
-
- zxlogf(TRACE, "SMC params 0x%X 0x%lX 0x%lX 0x%lX 0x%lX 0x%lX\n", params->func_id,
- params->arg1, params->arg2, params->arg3, params->arg4, params->arg5);
- status = zx_smc_call(smc_.get(), params, result);
- zxlogf(TRACE, "SMC busy_retry %d results %ld 0x%lX 0x%lX 0x%lX\n",
- busy_retries - busy_retry, result->arg0, result->arg1, result->arg2, result->arg3);
- }
- if (result->arg0 != 0) {
- zxlogf(ERROR, "%s error %d\n", __func__, static_cast<int>(result->arg0));
- }
- return status;
-}
-
zx_status_t PilDevice::Bind() {
auto status = pdev_.GetSmc(0, &smc_);
if (status != ZX_OK) {
@@ -255,7 +226,7 @@
auto params = CreatePilSmcParams(PilCmd::QuerySupport,
CreateSmcArgs(1, SmcArgType::kValue), i);
zx_smc_result_t result = {};
- status = SmcCall(¶ms, &result);
+ status = qcom::SmcCall(smc_.get(), ¶ms, &result);
if (status == ZX_OK && result.arg0 == kSmcOk && result.arg1 == 1) {
zxlogf(INFO, "%s pas_id %d supported\n", __func__, i);
}
diff --git a/zircon/system/dev/fw/qcom-pil/qcom-pil.h b/zircon/system/dev/fw/qcom-pil/qcom-pil.h
index 025bc17..04f8c13 100644
--- a/zircon/system/dev/fw/qcom-pil/qcom-pil.h
+++ b/zircon/system/dev/fw/qcom-pil/qcom-pil.h
@@ -101,10 +101,6 @@
constexpr uint8_t kCallMask = 0xFF;
constexpr uint8_t kCallShift = 0;
-constexpr uint64_t kSmcInterrupted = 1;
-constexpr uint64_t kSmcOk = 0;
-constexpr uint64_t kSmcBusy = -13;
-
static constexpr uint32_t CreateFunctionId(CallType call_type,
CallConvention call_conv,
Service service,
@@ -171,7 +167,6 @@
};
void ShutDown();
- zx_status_t SmcCall(zx_smc_parameters_t* params, zx_smc_result_t* result);
int PilThread();
zx_status_t LoadAuthFirmware(size_t fw_n);
diff --git a/zircon/system/dev/lib/qcom/BUILD.gn b/zircon/system/dev/lib/qcom/BUILD.gn
new file mode 100644
index 0000000..c7fa959
--- /dev/null
+++ b/zircon/system/dev/lib/qcom/BUILD.gn
@@ -0,0 +1,14 @@
+# Copyright 2019 The Fuchsia Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+library("qcom") {
+ sdk = "source"
+ sdk_headers = [ "qcom/smc.h" ]
+ sources = [
+ "qcom-smc.cpp",
+ ]
+ deps = [
+ "$zx/system/ulib/ddk",
+ ]
+}
diff --git a/zircon/system/dev/lib/qcom/include/qcom/smc.h b/zircon/system/dev/lib/qcom/include/qcom/smc.h
new file mode 100644
index 0000000..84bd559
--- /dev/null
+++ b/zircon/system/dev/lib/qcom/include/qcom/smc.h
@@ -0,0 +1,18 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#pragma once
+
+#include <zircon/syscalls.h>
+#include <zircon/syscalls/smc.h>
+#include <zircon/types.h>
+
+namespace qcom {
+ constexpr uint64_t kSmcInterrupted = 1;
+ constexpr uint64_t kSmcOk = 0;
+ constexpr uint64_t kSmcBusy = -13;
+
+ zx_status_t SmcCall(zx_handle_t h, zx_smc_parameters_t* params, zx_smc_result_t* result);
+
+} // namespace qcom
diff --git a/zircon/system/dev/lib/qcom/qcom-smc.cpp b/zircon/system/dev/lib/qcom/qcom-smc.cpp
new file mode 100644
index 0000000..3fe3bc7
--- /dev/null
+++ b/zircon/system/dev/lib/qcom/qcom-smc.cpp
@@ -0,0 +1,40 @@
+// Copyright 2019 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <ddk/debug.h>
+#include <qcom/smc.h>
+
+namespace qcom {
+
+zx_status_t SmcCall(zx_handle_t h, zx_smc_parameters_t* params, zx_smc_result_t* result) {
+ zxlogf(TRACE, "SMC params 0x%X 0x%lX 0x%lX 0x%lX 0x%lX 0x%lX\n", params->func_id,
+ params->arg1, params->arg2, params->arg3, params->arg4, params->arg5);
+ auto status = zx_smc_call(h, params, result);
+ zxlogf(TRACE, "SMC results %ld 0x%lX 0x%lX 0x%lX\n", result->arg0, result->arg1,
+ result->arg2, result->arg3);
+
+ constexpr int total_retry_msecs = 2000;
+ constexpr int busy_retry_msecs = 30;
+ constexpr int busy_retries = total_retry_msecs / busy_retry_msecs;
+ int busy_retry = busy_retries;
+ while (status == ZX_OK && // Wait forever for smc_interrupted, limited for smc_busy replies.
+ (result->arg0 == kSmcInterrupted || (result->arg0 == kSmcBusy && busy_retry--))) {
+ if (result->arg0 == kSmcBusy) {
+ zx_nanosleep(zx_deadline_after(ZX_MSEC(busy_retry_msecs)));
+ }
+ params->arg6 = result->arg6; // Pass optional session_id received via x6 back in retry.
+
+ zxlogf(TRACE, "SMC params 0x%X 0x%lX 0x%lX 0x%lX 0x%lX 0x%lX\n", params->func_id,
+ params->arg1, params->arg2, params->arg3, params->arg4, params->arg5);
+ status = zx_smc_call(h, params, result);
+ zxlogf(TRACE, "SMC busy_retry %d results %ld 0x%lX 0x%lX 0x%lX\n",
+ busy_retries - busy_retry, result->arg0, result->arg1, result->arg2,
+ result->arg3);
+ }
+ if (result->arg0 != 0) {
+ zxlogf(ERROR, "%s error %d\n", __func__, static_cast<int>(result->arg0));
+ }
+ return status;
+}
+} // namespace qcom