Signed-off-by: Jianhui Zhao <jianhui.zhao@gl-inet.com>
This commit is contained in:
Jianhui Zhao
2022-09-07 16:27:20 +08:00
parent 6190b4ad22
commit cc7705c272
22897 changed files with 4700846 additions and 9 deletions

6
.gitmodules vendored
View File

@@ -1,6 +0,0 @@
[submodule "u-boot"]
path = u-boot
url = https://github.com/mtk-openwrt/u-boot
[submodule "arm-trusted-firmware"]
path = arm-trusted-firmware
url = https://github.com/mtk-openwrt/arm-trusted-firmware

View File

@@ -1 +1 @@
# mt798x
# ATF and u-boot for GL.iNet products based on mt798x

View File

@@ -0,0 +1,91 @@
#
# Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
#
# Configure how the Linux checkpatch script should be invoked in the context of
# the Trusted Firmware source tree.
#
# This is not Linux so don't expect a Linux tree!
--no-tree
# The Linux kernel expects the SPDX license tag in the first line of each file.
# We don't follow this in the Trusted Firmware.
--ignore SPDX_LICENSE_TAG
# This clarifes the lines indications in the report.
#
# E.g.:
# Without this option, we have the following output:
# #333: FILE: drivers/arm/gic/arm_gic.c:160:
# So we have 2 lines indications (333 and 160), which is confusing.
# We only care about the position in the source file.
#
# With this option, it becomes:
# drivers/arm/gic/arm_gic.c:160:
--showfile
# Don't show some messages like the list of ignored types or the suggestion to
# use "--fix" or report changes to the maintainers.
--quiet
#
# Ignore the following message types, as they don't necessarily make sense in
# the context of the Trusted Firmware.
#
# COMPLEX_MACRO generates false positives.
--ignore COMPLEX_MACRO
# Commit messages might contain a Gerrit Change-Id.
--ignore GERRIT_CHANGE_ID
# Do not check the format of commit messages, as Gerrit's merge commits do not
# preserve it.
--ignore GIT_COMMIT_ID
# FILE_PATH_CHANGES reports this kind of message:
# "added, moved or deleted file(s), does MAINTAINERS need updating?"
# We do not use this MAINTAINERS file process in TF.
--ignore FILE_PATH_CHANGES
# AVOID_EXTERNS reports this kind of messages:
# "externs should be avoided in .c files"
# We don't follow this convention in TF.
--ignore AVOID_EXTERNS
# NEW_TYPEDEFS reports this kind of messages:
# "do not add new typedefs"
# We allow adding new typedefs in TF.
--ignore NEW_TYPEDEFS
# Avoid "Does not appear to be a unified-diff format patch" message
--ignore NOT_UNIFIED_DIFF
# VOLATILE reports this kind of messages:
# "Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt"
# We allow the usage of the volatile keyword in TF.
--ignore VOLATILE
# BRACES reports this kind of messages:
# braces {} are not necessary for any arm of this statement
--ignore BRACES
# PREFER_KERNEL_TYPES reports this kind of messages (when using --strict):
# "Prefer kernel type 'u32' over 'uint32_t'"
--ignore PREFER_KERNEL_TYPES
# USLEEP_RANGE reports this kind of messages (when using --strict):
# "usleep_range is preferred over udelay; see Documentation/timers/timers-howto.txt"
--ignore USLEEP_RANGE
# COMPARISON_TO_NULL reports this kind of messages (when using --strict):
# Comparison to NULL could be written ""
--ignore COMPARISON_TO_NULL
# UNNECESSARY_PARENTHESES reports this kind of messages (when using --strict):
# Unnecessary parentheses around ""
--ignore UNNECESSARY_PARENTHESES

View File

@@ -0,0 +1,73 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* eslint-env es6 */
"use strict";
const fs = require("fs");
const yaml = require("js-yaml");
const { "trailer-exists": trailerExists } = require("@commitlint/rules").default;
/*
* The types and scopes accepted by both Commitlint and Commitizen are defined by the changelog
* configuration file - `changelog.yaml` - as they decide which section of the changelog commits
* with a given type and scope are placed in.
*/
let changelog;
try {
const contents = fs.readFileSync("changelog.yaml", "utf8");
changelog = yaml.load(contents);
} catch (err) {
console.log(err);
throw err;
}
function getTypes(sections) {
return sections.map(section => section.type)
}
function getScopes(subsections) {
return subsections.flatMap(subsection => {
const scope = subsection.scope ? [ subsection.scope ] : [];
const subscopes = getScopes(subsection.subsections || []);
return scope.concat(subscopes);
})
};
const types = getTypes(changelog.sections).sort(); /* Sort alphabetically */
const scopes = getScopes(changelog.subsections).sort(); /* Sort alphabetically */
module.exports = {
extends: ["@commitlint/config-conventional"],
plugins: [
{
rules: {
"signed-off-by-exists": trailerExists,
"change-id-exists": trailerExists,
},
},
],
rules: {
"header-max-length": [1, "always", 50], /* Warning */
"body-max-line-length": [1, "always", 72], /* Warning */
"change-id-exists": [1, "always", "Change-Id:"], /* Warning */
"signed-off-by-exists": [1, "always", "Signed-off-by:"], /* Warning */
"type-case": [2, "always", "lower-case" ], /* Error */
"type-enum": [2, "always", types], /* Error */
"scope-case": [2, "always", "lower-case"], /* Error */
"scope-enum": [1, "always", scopes] /* Warning */
},
};

View File

@@ -0,0 +1,3 @@
{
"path": "@commitlint/cz-commitlint"
}

View File

@@ -0,0 +1,72 @@
#
# Copyright (c) 2017-2020, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# Trusted Firmware-A Coding style spec for editors.
# References:
# [EC] http://editorconfig.org/
# [CONT] contributing.rst
# [LCS] Linux Coding Style
# (https://www.kernel.org/doc/html/v4.10/process/coding-style.html)
# [PEP8] Style Guide for Python Code
# (https://www.python.org/dev/peps/pep-0008)
root = true
# set default to match [LCS] .c/.h settings.
# This will also apply to .S, .mk, .sh, Makefile, .dts, etc.
[*]
# Not specified, but fits current ARM-TF sources.
charset = utf-8
# Not specified, but implicit for "LINUX coding style".
end_of_line = lf
# [LCS] Chapter 1: Indentation
# "and thus indentations are also 8 characters"
indent_size = 8
# [LCS] Chapter 1: Indentation
# "Outside of comments,...spaces are never used for indentation"
indent_style = tab
# Not specified by [LCS], but sensible
insert_final_newline = true
# [LCS] Chapter 2: Breaking long lines and strings
# "The limit on the length of lines is 100 columns"
# This is a "soft" requirement for Arm-TF, and should not be the sole
# reason for changes.
max_line_length = 100
# [LCS] Chapter 1: Indentation
# "Tabs are 8 characters"
tab_width = 8
# [LCS] Chapter 1: Indentation
# "Get a decent editor and don't leave whitespace at the end of lines."
# [LCS] Chapter 3.1: Spaces
# "Do not leave trailing whitespace at the ends of lines."
trim_trailing_whitespace = true
# Adjustment for ReStructuredText (RST) documentation
[*.{rst}]
indent_size = 4
indent_style = space
# Adjustment for python which prefers a different style
[*.py]
# [PEP8] Indentation
# "Use 4 spaces per indentation level."
indent_size = 4
indent_style = space
# [PEP8] Maximum Line Length
# "Limit all lines to a maximum of 79 characters."
max_line_length = 79

45
atf-20220606-637ba581b/.gitignore vendored Normal file
View File

@@ -0,0 +1,45 @@
# Ignore miscellaneous files
cscope.*
*.swp
*.patch
*~
.project
.cproject
# Ignore build directory
build/
# Ignore build products from tools
tools/**/*.o
tools/renesas/rcar_layout_create/*.bin
tools/renesas/rcar_layout_create/*.srec
tools/renesas/rcar_layout_create/*.map
tools/renesas/rcar_layout_create/*.elf
tools/renesas/rzg_layout_create/*.bin
tools/renesas/rzg_layout_create/*.srec
tools/renesas/rzg_layout_create/*.map
tools/renesas/rzg_layout_create/*.elf
tools/fiptool/fiptool
tools/fiptool/fiptool.exe
tools/cert_create/src/*.o
tools/cert_create/src/**/*.o
tools/cert_create/cert_create
tools/cert_create/cert_create.exe
tools/marvell/doimage/doimage
tools/amlogic/doimage
tools/stm32image/*.o
tools/stm32image/stm32image
tools/stm32image/stm32image.exe
tools/sptool/__pycache__/
# GNU GLOBAL files
GPATH
GRTAGS
GSYMS
GTAGS
# Ctags
tags
# Node.js
node_modules/

View File

@@ -0,0 +1,5 @@
[gerrit]
host=review.trustedfirmware.org
port=29418
project=TF-A/trusted-firmware-a
defaultbranch=integration

View File

@@ -0,0 +1 @@
_

View File

@@ -0,0 +1,7 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
"$(dirname "$0")/commit-msg.gerrit" "$@"
"$(dirname "$0")/commit-msg.commitlint" "$@"

View File

@@ -0,0 +1,3 @@
#!/bin/sh
npx --no-install commitlint --edit "$1"

View File

@@ -0,0 +1,194 @@
#!/bin/sh
# From Gerrit Code Review 2.14.20
#
# Part of Gerrit Code Review (https://www.gerritcodereview.com/)
#
# Copyright (C) 2009 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.
#
unset GREP_OPTIONS
CHANGE_ID_AFTER="Bug|Depends-On|Issue|Test|Feature|Fixes|Fixed"
MSG="$1"
# Check for, and add if missing, a unique Change-Id
#
add_ChangeId() {
clean_message=`sed -e '
/^diff --git .*/{
s///
q
}
/^Signed-off-by:/d
/^#/d
' "$MSG" | git stripspace`
if test -z "$clean_message"
then
return
fi
# Do not add Change-Id to temp commits
if echo "$clean_message" | head -1 | grep -q '^\(fixup\|squash\)!'
then
return
fi
if test "false" = "`git config --bool --get gerrit.createChangeId`"
then
return
fi
# Does Change-Id: already exist? if so, exit (no change).
if grep -i '^Change-Id:' "$MSG" >/dev/null
then
return
fi
id=`_gen_ChangeId`
T="$MSG.tmp.$$"
AWK=awk
if [ -x /usr/xpg4/bin/awk ]; then
# Solaris AWK is just too broken
AWK=/usr/xpg4/bin/awk
fi
# Get core.commentChar from git config or use default symbol
commentChar=`git config --get core.commentChar`
commentChar=${commentChar:-#}
# How this works:
# - parse the commit message as (textLine+ blankLine*)*
# - assume textLine+ to be a footer until proven otherwise
# - exception: the first block is not footer (as it is the title)
# - read textLine+ into a variable
# - then count blankLines
# - once the next textLine appears, print textLine+ blankLine* as these
# aren't footer
# - in END, the last textLine+ block is available for footer parsing
$AWK '
BEGIN {
if (match(ENVIRON["OS"], "Windows")) {
RS="\r?\n" # Required on recent Cygwin
}
# while we start with the assumption that textLine+
# is a footer, the first block is not.
isFooter = 0
footerComment = 0
blankLines = 0
}
# Skip lines starting with commentChar without any spaces before it.
/^'"$commentChar"'/ { next }
# Skip the line starting with the diff command and everything after it,
# up to the end of the file, assuming it is only patch data.
# If more than one line before the diff was empty, strip all but one.
/^diff --git / {
blankLines = 0
while (getline) { }
next
}
# Count blank lines outside footer comments
/^$/ && (footerComment == 0) {
blankLines++
next
}
# Catch footer comment
/^\[[a-zA-Z0-9-]+:/ && (isFooter == 1) {
footerComment = 1
}
/]$/ && (footerComment == 1) {
footerComment = 2
}
# We have a non-blank line after blank lines. Handle this.
(blankLines > 0) {
print lines
for (i = 0; i < blankLines; i++) {
print ""
}
lines = ""
blankLines = 0
isFooter = 1
footerComment = 0
}
# Detect that the current block is not the footer
(footerComment == 0) && (!/^\[?[a-zA-Z0-9-]+:/ || /^[a-zA-Z0-9-]+:\/\//) {
isFooter = 0
}
{
# We need this information about the current last comment line
if (footerComment == 2) {
footerComment = 0
}
if (lines != "") {
lines = lines "\n";
}
lines = lines $0
}
# Footer handling:
# If the last block is considered a footer, splice in the Change-Id at the
# right place.
# Look for the right place to inject Change-Id by considering
# CHANGE_ID_AFTER. Keys listed in it (case insensitive) come first,
# then Change-Id, then everything else (eg. Signed-off-by:).
#
# Otherwise just print the last block, a new line and the Change-Id as a
# block of its own.
END {
unprinted = 1
if (isFooter == 0) {
print lines "\n"
lines = ""
}
changeIdAfter = "^(" tolower("'"$CHANGE_ID_AFTER"'") "):"
numlines = split(lines, footer, "\n")
for (line = 1; line <= numlines; line++) {
if (unprinted && match(tolower(footer[line]), changeIdAfter) != 1) {
unprinted = 0
print "Change-Id: I'"$id"'"
}
print footer[line]
}
if (unprinted) {
print "Change-Id: I'"$id"'"
}
}' "$MSG" > "$T" && mv "$T" "$MSG" || rm -f "$T"
}
_gen_ChangeIdInput() {
echo "tree `git write-tree`"
if parent=`git rev-parse "HEAD^0" 2>/dev/null`
then
echo "parent $parent"
fi
echo "author `git var GIT_AUTHOR_IDENT`"
echo "committer `git var GIT_COMMITTER_IDENT`"
echo
printf '%s' "$clean_message"
}
_gen_ChangeId() {
_gen_ChangeIdInput |
git hash-object -t commit --stdin
}
add_ChangeId

View File

@@ -0,0 +1,6 @@
#!/bin/sh
# shellcheck source=./_/husky.sh
. "$(dirname "$0")/_/husky.sh"
"$(dirname "$0")/prepare-commit-msg.cz" "$@"

View File

@@ -0,0 +1,28 @@
#!/bin/bash
file="$1"
type="$2"
if [ -z "$type" ]; then # only run on new commits
#
# Save any commit message trailers generated by Git.
#
trailers=$(git interpret-trailers --parse "$file")
#
# Execute the Commitizen hook.
#
(exec < "/dev/tty" && npx --no-install git-cz --hook) || true
#
# Restore any trailers that Commitizen might have overwritten.
#
printf "\n" >> "$file"
while IFS= read -r trailer; do
git interpret-trailers --in-place --trailer "$trailer" "$file"
done <<< "$trailers"
fi

View File

@@ -0,0 +1 @@
637ba581b4a192e72c77fb0a315244ea9e420cb9

View File

@@ -0,0 +1,113 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* eslint-env es6 */
"use strict";
const fs = require("fs");
const yaml = require("js-yaml");
/*
* The types and scopes accepted by both Commitlint and Commitizen are defined by the changelog
* configuration file - `changelog.yaml` - as they decide which section of the changelog commits
* with a given type and scope are placed in.
*/
let changelog;
try {
const contents = fs.readFileSync("changelog.yaml", "utf8");
changelog = yaml.load(contents);
} catch (err) {
console.log(err);
throw err;
}
/*
* The next couple of functions are just used to transform the changelog YAML configuration
* structure into one accepted by the Conventional Changelog adapter (conventional-changelog-tf-a).
*/
function getTypes(sections) {
return sections.map(section => {
return {
"type": section.type,
"section": section.hidden ? undefined : section.title,
"hidden": section.hidden || false,
};
})
}
function getSections(subsections) {
return subsections.flatMap(subsection => {
const scope = subsection.scope ? [ subsection.scope ] : [];
return {
"title": subsection.title,
"sections": getSections(subsection.subsections || []),
"scopes": scope.concat(subsection.deprecated || []),
};
})
};
const types = getTypes(changelog.sections);
const sections = getSections(changelog.subsections);
module.exports = {
"header": "# Change Log & Release Notes\n\nThis document contains a summary of the new features, changes, fixes and known\nissues in each release of Trusted Firmware-A.\n",
"preset": {
"name": "tf-a",
"commitUrlFormat": "https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/{{hash}}",
"compareUrlFormat": "https://review.trustedfirmware.org/plugins/gitiles/TF-A/trusted-firmware-a/+/refs/tags/{{previousTag}}..refs/tags/{{currentTag}}",
"userUrlFormat": "https://github.com/{{user}}",
"types": types,
"sections": sections,
},
"infile": "docs/change-log.md",
"skip": {
"commit": true,
"tag": true
},
"bumpFiles": [
{
"filename": "package.json",
"type": "json"
},
{
"filename": "package-lock.json",
"type": "json"
},
{
"filename": "tools/conventional-changelog-tf-a/package.json",
"type": "json"
},
{
"filename": "Makefile",
"updater": {
"readVersion": function (contents) {
const major = contents.match(/^VERSION_MAJOR\s*:=\s*(\d+?)$/m)[1];
const minor = contents.match(/^VERSION_MINOR\s*:=\s*(\d+?)$/m)[1];
return `${major}.${minor}.0`;
},
"writeVersion": function (contents, version) {
const major = version.split(".")[0];
const minor = version.split(".")[1];
contents = contents.replace(/^(VERSION_MAJOR\s*:=\s*)(\d+?)$/m, `$1${major}`);
contents = contents.replace(/^(VERSION_MINOR\s*:=\s*)(\d+?)$/m, `$1${minor}`);
return contents;
}
}
}
]
};

View File

@@ -0,0 +1,5 @@
Copyright (c) 2011-2019, Ulf Magnusson <ulfalizer@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

View File

@@ -0,0 +1,2 @@
# Include the license file in source distributions
include LICENSE.txt

View File

@@ -0,0 +1,841 @@
.. contents:: Table of contents
:backlinks: none
News
----
Dependency loop with recent linux-next kernels
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To fix issues with dependency loops on recent linux-next kernels, apply `this
patch <https://www.spinics.net/lists/linux-kbuild/msg23455.html>`_. Hopefully,
it will be in ``linux-next`` soon.
``windows-curses`` is no longer automatically installed on Windows
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Starting with Kconfiglib 13.0.0, the `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ package is no longer
automatically installed on Windows, and needs to be installed manually for the
terminal ``menuconfig`` to work.
This fixes installation of Kconfiglib on MSYS2, which is not compatible with
``windows-curses``. See `this issue
<https://github.com/ulfalizer/Kconfiglib/issues/77>`__.
The ``menuconfig`` now shows a hint re. installing ``windows-curses`` when the
``curses`` module can't be imported on Windows.
Sorry if this change caused problems!
Overview
--------
Kconfiglib is a `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
implementation in Python 2/3. It started out as a helper library, but now has a
enough functionality to also work well as a standalone Kconfig implementation
(including `terminal and GUI menuconfig interfaces <Menuconfig interfaces_>`_
and `Kconfig extensions`_).
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_. The
bundled scripts are implemented on top of it. Implementing your own scripts
should be relatively easy, if needed.
Kconfiglib is used exclusively by e.g. the `Zephyr
<https://www.zephyrproject.org/>`__, `esp-idf
<https://github.com/espressif/esp-idf>`__, and `ACRN
<https://projectacrn.org/>`__ projects. It is also used for many small helper
scripts in various projects.
Since Kconfiglib is based around a library, it can be used e.g. to generate a
`Kconfig cross-reference
<https://docs.zephyrproject.org/latest/reference/kconfig/index.html>`_, using
the same robust Kconfig parser used for other Kconfig tools, instead of brittle
ad-hoc parsing. The documentation generation script can be found `here
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`__.
Kconfiglib implements the recently added `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__.
For backwards compatibility, environment variables can be referenced both as
``$(FOO)`` (the new syntax) and as ``$FOO`` (the old syntax). The old syntax is
deprecated, but will probably be supported for a long time, as it's needed to
stay compatible with older Linux kernels. The major version will be increased
if support is ever dropped. Using the old syntax with an undefined environment
variable keeps the string as is.
Note: See `this issue <https://github.com/ulfalizer/Kconfiglib/issues/47>`__ if
you run into a "macro expanded to blank string" error with kernel 4.18+.
See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
Kconfig tips and best practices.
Installation
------------
Installation with pip
~~~~~~~~~~~~~~~~~~~~~
Kconfiglib is available on `PyPI <https://pypi.python.org/pypi/kconfiglib/>`_ and can be
installed with e.g.
.. code::
$ pip(3) install kconfiglib
Microsoft Windows is supported.
The ``pip`` installation will give you both the base library and the following
executables. All but two (``genconfig`` and ``setconfig``) mirror functionality
available in the C tools.
- `menuconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
- `guiconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_
- `oldconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/oldconfig.py>`_
- `olddefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/olddefconfig.py>`_
- `savedefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/savedefconfig.py>`_
- `defconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/defconfig.py>`_
- `alldefconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/alldefconfig.py>`_
- `allnoconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_
- `allmodconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allmodconfig.py>`_
- `allyesconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
- `listnewconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/listnewconfig.py>`_
- `genconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/genconfig.py>`_
- `setconfig <https://github.com/ulfalizer/Kconfiglib/blob/master/setconfig.py>`_
``genconfig`` is intended to be run at build time. It generates a C header from
the configuration and (optionally) information that can be used to rebuild only
files that reference Kconfig symbols that have changed value.
Starting with Kconfiglib version 12.2.0, all utilities are compatible with both
Python 2 and Python 3. Previously, ``menuconfig.py`` only ran under Python 3
(i.e., it's now more backwards compatible than before).
**Note:** If you install Kconfiglib with ``pip``'s ``--user`` flag, make sure
that your ``PATH`` includes the directory where the executables end up. You can
list the installed files with ``pip(3) show -f kconfiglib``.
All releases have a corresponding tag in the git repository, e.g. ``v14.1.0``
(the latest version).
`Semantic versioning <http://semver.org/>`_ is used. There's been ten small
changes to the behavior of the API, a Windows packaging change, and a hashbang
change to use ``python3``
(`1 <https://github.com/ulfalizer/Kconfiglib/commit/e8b4ecb6ff6ccc1c7be0818314fbccda2ef2b2ee>`_,
`2 <https://github.com/ulfalizer/Kconfiglib/commit/db633015a4d7b0ba1e882f665e191f350932b2af>`_,
`3 <https://github.com/ulfalizer/Kconfiglib/commit/8983f7eb297dd614faf0beee3129559bc8ba338e>`_,
`4 <https://github.com/ulfalizer/Kconfiglib/commit/cbf32e29a130d22bc734b7778e6304ac9df2a3e8>`_,
`5 <https://github.com/ulfalizer/Kconfiglib/commit/eb6c21a9b33a2d6e2bed9882d4f930d0cab2f03b>`_,
`6 <https://github.com/ulfalizer/Kconfiglib/commit/c19fc11355b13d75d97286402c7a933fb23d3b70>`_,
`7 <https://github.com/ulfalizer/Kconfiglib/commit/7a428aa415606820a44291f475248b08e3952c4b>`_,
`8 <https://github.com/ulfalizer/Kconfiglib/commit/f247ddf618ad29718e5efd3e69f8baf75d4d347b>`_,
`9 <https://github.com/ulfalizer/Kconfiglib/commit/4fed39d9271ceb68be4157ab3f96a45b94f77dc0>`_,
`10 <https://github.com/ulfalizer/Kconfiglib/commit/55bc8c380869ea663092212e8fe388ad7abae596>`_,
`Windows packaging change <https://github.com/ulfalizer/Kconfiglib/commit/21b4c1e3b6e2867b9a0788d21a358f6b1f581d86>`_,
`Python 3 hashbang change <https://github.com/ulfalizer/Kconfiglib/commit/9e0a8d29fa76adcb3f27bb2e20f16fefc2a8591e>`_),
which is why the major version is at 14 rather than 2. I do major version bumps
for all behavior changes, even tiny ones, and most of these were fixes for baby
issues in the early days of the Kconfiglib 2 API.
Manual installation
~~~~~~~~~~~~~~~~~~~
Just drop ``kconfiglib.py`` and the scripts you want somewhere. There are no
third-party dependencies, but the terminal ``menuconfig`` won't work on Windows
unless a package like `windows-curses
<https://github.com/zephyrproject-rtos/windows-curses>`__ is installed.
Installation for the Linux kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
See the module docstring at the top of `kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
Python version compatibility (2.7/3.2+)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Kconfiglib and all utilities run under both Python 2.7 and Python 3.2 and
later. The code mostly uses basic Python features and has no third-party
dependencies, so keeping it backwards-compatible is pretty low effort.
The 3.2 requirement comes from ``argparse``. ``format()`` with unnumbered
``{}`` is used as well.
A recent Python 3 version is recommended if you have a choice, as it'll give
you better Unicode handling.
Getting started
---------------
1. `Install <Installation_>`_ the library and the utilities.
2. Write `Kconfig
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-language.rst>`__
files that describe the available configuration options. See `this page
<https://docs.zephyrproject.org/latest/guides/kconfig/tips.html>`__ for some
general Kconfig advice.
3. Generate an initial configuration with e.g. ``menuconfig``/``guiconfig`` or
``alldefconfig``. The configuration is saved as ``.config`` by default.
For more advanced projects, the ``defconfig`` utility can be used to
generate the initial configuration from an existing configuration file.
Usually, this existing configuration file would be a minimal configuration
file, as generated by e.g. ``savedefconfig``.
4. Run ``genconfig`` to generate a header file. By default, it is saved as
``config.h``.
Normally, ``genconfig`` would be run automatically as part of the build.
Before writing a header file or other configuration output, Kconfiglib
compares the old contents of the file against the new contents. If there's
no change, the write is skipped. This avoids updating file metadata like the
modification time, and might save work depending on your build setup.
Adding new configuration output formats should be relatively straightforward.
See the implementation of ``write_config()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The documentation for the ``Symbol.config_string`` property has some tips as
well.
5. To update an old ``.config`` file after the Kconfig files have changed (e.g.
to add new options), run ``oldconfig`` (prompts for values for new options)
or ``olddefconfig`` (gives new options their default value). Entering the
``menuconfig`` or ``guiconfig`` interface and saving the configuration will
also update it (the configuration interfaces always prompt for saving
on exit if it would modify the contents of the ``.config`` file).
Due to Kconfig semantics, simply loading an old ``.config`` file performs an
implicit ``olddefconfig``, so building will normally not be affected by
having an outdated configuration.
Whenever ``.config`` is overwritten, the previous version of the file is saved
to ``.config.old`` (or, more generally, to ``$KCONFIG_CONFIG.old``).
Using ``.config`` files as Make input
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``.config`` files use Make syntax and can be included directly in Makefiles to
read configuration values from there. This is why ``n``-valued
``bool``/``tristate`` values are written out as ``# CONFIG_FOO is not set`` (a
Make comment) in ``.config``, allowing them to be tested with ``ifdef`` in
Make.
If you make use of this, you might want to pass ``--config-out <filename>`` to
``genconfig`` and include the configuration file it generates instead of
including ``.config`` directly. This has the advantage that the generated
configuration file will always be a "full" configuration file, even if
``.config`` is outdated. Otherwise, it might be necessary to run
``old(def)config`` or ``menuconfig``/``guiconfig`` before rebuilding with an
outdated ``.config``.
If you use ``--sync-deps`` to generate incremental build information, you can
include ``deps/auto.conf`` instead, which is also a full configuration file.
Useful helper macros
~~~~~~~~~~~~~~~~~~~~
The `include/linux/kconfig.h
<https://github.com/torvalds/linux/blob/master/include/linux/kconfig.h>`_
header in the Linux kernel defines some useful helper macros for testing
Kconfig configuration values.
``IS_ENABLED()`` is generally useful, allowing configuration values to be
tested in ``if`` statements with no runtime overhead.
Incremental building
~~~~~~~~~~~~~~~~~~~~
See the docstring for ``Kconfig.sync_deps()`` in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_ for hints
on implementing incremental builds (rebuilding just source files that reference
changed configuration values).
Running the ``scripts/basic/fixdep.c`` tool from the kernel on the output of
``gcc -MD <source file>`` might give you an idea of how it all fits together.
Library documentation
---------------------
Kconfiglib comes with extensive documentation in the form of docstrings. To view it, run e.g.
the following command:
.. code:: sh
$ pydoc(3) kconfiglib
For HTML output, add ``-w``:
.. code:: sh
$ pydoc(3) -w kconfiglib
This will also work after installing Kconfiglib with ``pip(3)``.
Documentation for other modules can be viewed in the same way (though a plain
``--help`` will work when they're run as executables):
.. code:: sh
$ pydoc(3) menuconfig/guiconfig/...
A good starting point for learning the library is to read the module docstring
(which you could also just read directly at the beginning of `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_). It
gives an introduction to symbol values, the menu tree, and expressions.
After reading the module docstring, a good next step is to read the ``Kconfig``
class documentation, and then the documentation for the ``Symbol``, ``Choice``,
and ``MenuNode`` classes.
Please tell me if something is unclear or can be explained better.
Library features
----------------
Kconfiglib can do the following, among other things:
- **Programmatically get and set symbol values**
See `allnoconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allnoconfig.py>`_ and
`allyesconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_,
which are automatically verified to produce identical output to the standard
``make allnoconfig`` and ``make allyesconfig``.
- **Read and write .config and defconfig files**
The generated ``.config`` and ``defconfig`` (minimal configuration) files are
character-for-character identical to what the C implementation would generate
(except for the header comment). The test suite relies on this, as it
compares the generated files.
- **Write C headers**
The generated headers use the same format as ``include/generated/autoconf.h``
from the Linux kernel. Output for symbols appears in the order that they're
defined, unlike in the C tools (where the order depends on the hash table
implementation).
- **Implement incremental builds**
This uses the same scheme as the ``include/config`` directory in the kernel:
Symbols are translated into files that are touched when the symbol's value
changes between builds, which can be used to avoid having to do a full
rebuild whenever the configuration is changed.
See the ``sync_deps()`` function for more information.
- **Inspect symbols**
Printing a symbol or other item (which calls ``__str__()``) returns its
definition in Kconfig format. This also works for symbols defined in multiple
locations.
A helpful ``__repr__()`` is on all objects too.
All ``__str__()`` and ``__repr__()`` methods are deliberately implemented
with just public APIs, so all symbol information can be fetched separately as
well.
- **Inspect expressions**
Expressions use a simple tuple-based format that can be processed manually
if needed. Expression printing and evaluation functions are provided,
implemented with public APIs.
- **Inspect the menu tree**
The underlying menu tree is exposed, including submenus created implicitly
from symbols depending on preceding symbols. This can be used e.g. to
implement menuconfig-like functionality.
See `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_/`guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ and the
minimalistic `menuconfig_example.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.py>`_
example.
Kconfig extensions
~~~~~~~~~~~~~~~~~~
The following Kconfig extensions are available:
- ``source`` supports glob patterns and includes each matching file. A pattern
is required to match at least one file.
A separate ``osource`` statement is available for cases where it's okay for
the pattern to match no files (in which case ``osource`` turns into a no-op).
- A relative ``source`` statement (``rsource``) is available, where file paths
are specified relative to the directory of the current Kconfig file. An
``orsource`` statement is available as well, analogous to ``osource``.
- Preprocessor user functions can be defined in Python, which makes it simple
to integrate information from existing Python tools into Kconfig (e.g. to
have Kconfig symbols depend on hardware information stored in some other
format).
See the *Kconfig extensions* section in the
`kconfiglib.py <https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_
module docstring for more information.
- ``def_int``, ``def_hex``, and ``def_string`` are available in addition to
``def_bool`` and ``def_tristate``, allowing ``int``, ``hex``, and ``string``
symbols to be given a type and a default at the same time.
These can be useful in projects that make use of symbols defined in multiple
locations, and remove some Kconfig inconsistency.
- Environment variables are expanded directly in e.g. ``source`` and
``mainmenu`` statements, meaning ``option env`` symbols are redundant.
This is the standard behavior with the new `Kconfig preprocessor
<https://github.com/torvalds/linux/blob/master/Documentation/kbuild/kconfig-macro-language.rst>`__,
which Kconfiglib implements.
``option env`` symbols are accepted but ignored, which leads the caveat that
they must have the same name as the environment variables they reference
(Kconfiglib warns if the names differ). This keeps Kconfiglib compatible with
older Linux kernels, where the name of the ``option env`` symbol always
matched the environment variable. Compatibility with older Linux kernels is
the main reason ``option env`` is still supported.
The C tools have dropped support for ``option env``.
- Two extra optional warnings can be enabled by setting environment variables,
covering cases that are easily missed when making changes to Kconfig files:
* ``KCONFIG_WARN_UNDEF``: If set to ``y``, warnings will be generated for all
references to undefined symbols within Kconfig files. The only gotcha is
that all hex literals must be prefixed with ``0x`` or ``0X``, to make it
possible to distinguish them from symbol references.
Some projects (e.g. the Linux kernel) use multiple Kconfig trees with many
shared Kconfig files, leading to some safe undefined symbol references.
``KCONFIG_WARN_UNDEF`` is useful in projects that only have a single
Kconfig tree though.
``KCONFIG_STRICT`` is an older alias for this environment variable,
supported for backwards compatibility.
* ``KCONFIG_WARN_UNDEF_ASSIGN``: If set to ``y``, warnings will be generated
for all assignments to undefined symbols within ``.config`` files. By
default, no such warnings are generated.
This warning can also be enabled/disabled by setting
``Kconfig.warn_assign_undef`` to ``True``/``False``.
Other features
--------------
- **Single-file implementation**
The entire library is contained in `kconfiglib.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/kconfiglib.py>`_.
The tools implemented on top of it are one file each.
- **Robust and highly compatible with the C Kconfig tools**
 The `test suite <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
automatically compares output from Kconfiglib and the C tools
by diffing the generated ``.config`` files for the real kernel Kconfig and
defconfig files, for all ARCHes.
This currently involves comparing the output for 36 ARCHes and 498 defconfig
files (or over 18000 ARCH/defconfig combinations in "obsessive" test suite
mode). All tests are expected to pass.
A comprehensive suite of selftests is included as well.
- **Not horribly slow despite being a pure Python implementation**
The `allyesconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/allyesconfig.py>`_
script currently runs in about 1.3 seconds on the Linux kernel on a Core i7
2600K (with a warm file cache), including the ``make`` overhead from ``make
scriptconfig``. Note that the Linux kernel Kconfigs are absolutely massive
(over 14k symbols for x86) compared to most projects, and also have overhead
from running shell commands via the Kconfig preprocessor.
Kconfiglib is especially speedy in cases where multiple ``.config`` files
need to be processed, because the ``Kconfig`` files will only need to be parsed
once.
For long-running jobs, `PyPy <https://pypy.org/>`_ gives a big performance
boost. CPython is faster for short-running jobs as PyPy needs some time to
warm up.
Kconfiglib also works well with the
`multiprocessing <https://docs.python.org/3/library/multiprocessing.html>`_
module. No global state is kept.
- **Generates more warnings than the C implementation**
Generates the same warnings as the C implementation, plus additional ones.
Also detects dependency and ``source`` loops.
All warnings point out the location(s) in the ``Kconfig`` files where a
symbol is defined, where applicable.
- **Unicode support**
Unicode characters in string literals in ``Kconfig`` and ``.config`` files are
correctly handled. This support mostly comes for free from Python.
- **Windows support**
Nothing Linux-specific is used. Universal newlines mode is used for both
Python 2 and Python 3.
The `Zephyr <https://www.zephyrproject.org/>`_ project uses Kconfiglib to
generate ``.config`` files and C headers on Linux as well as Windows.
- **Internals that (mostly) mirror the C implementation**
While being simpler to understand and tweak.
Menuconfig interfaces
---------------------
Three configuration interfaces are currently available:
- `menuconfig.py <https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_
is a terminal-based configuration interface implemented using the standard
Python ``curses`` module. ``xconfig`` features like showing invisible symbols and
showing symbol names are included, and it's possible to jump directly to a symbol
in the menu tree (even if it's currently invisible).
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/menuconfig.gif
*There is now also a show-help mode that shows the help text of the currently
selected symbol in the help window at the bottom.*
Starting with Kconfiglib 12.2.0, ``menuconfig.py`` runs under both Python 2
and Python 3 (previously, it only ran under Python 3, so this was a
backport). Running it under Python 3 provides better support for Unicode text
entry (``get_wch()`` is not available in the ``curses`` module on Python 2).
There are no third-party dependencies on \*nix. On Windows,
the ``curses`` modules is not available by default, but support
can be added by installing the ``windows-curses`` package:
.. code-block:: shell
$ pip install windows-curses
This uses wheels built from `this repository
<https://github.com/zephyrproject-rtos/windows-curses>`_, which is in turn
based on Christoph Gohlke's `Python Extension Packages for Windows
<https://www.lfd.uci.edu/~gohlke/pythonlibs/#curses>`_.
See the docstring at the top of `menuconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/menuconfig.py>`_ for
more information about the terminal menuconfig implementation.
- `guiconfig.py
<https://github.com/ulfalizer/Kconfiglib/blob/master/guiconfig.py>`_ is a
graphical configuration interface written in `Tkinter
<https://docs.python.org/3/library/tkinter.html>`_. Like ``menuconfig.py``,
it supports showing all symbols (with invisible symbols in red) and jumping
directly to symbols. Symbol values can also be changed directly from the
jump-to dialog.
When single-menu mode is enabled, a single menu is shown at a time, like in
the terminal menuconfig. Only this mode distinguishes between symbols defined
with ``config`` and symbols defined with ``menuconfig``.
``guiconfig.py`` has been tested on X11, Windows, and macOS, and is
compatible with both Python 2 and Python 3.
Despite being part of the Python standard library, ``tkinter`` often isn't
included by default in Python installations on Linux. These commands will
install it on a few different distributions:
- Ubuntu: ``sudo apt install python-tk``/``sudo apt install python3-tk``
- Fedora: ``dnf install python2-tkinter``/``dnf install python3-tkinter``
- Arch: ``sudo pacman -S tk``
- Clear Linux: ``sudo swupd bundle-add python3-tcl``
Screenshot below, with show-all mode enabled and the jump-to dialog open:
.. image:: https://raw.githubusercontent.com/ulfalizer/Kconfiglib/screenshots/screenshots/guiconfig.png
To avoid having to carry around a bunch of GIFs, the image data is embedded
in ``guiconfig.py``. To use separate GIF files instead, change
``_USE_EMBEDDED_IMAGES`` to ``False`` in ``guiconfig.py``. The image files
can be found in the `screenshots
<https://github.com/ulfalizer/Kconfiglib/tree/screenshots/guiconfig>`_
branch.
I did my best with the images, but some are definitely only art adjacent.
Touch-ups are welcome. :)
- `pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_, built by `RomaVis
<https://github.com/RomaVis>`_, is an older portable Python 2/3 TkInter
menuconfig implementation.
Screenshot below:
.. image:: https://raw.githubusercontent.com/RomaVis/pymenuconfig/master/screenshot.PNG
While working on the terminal menuconfig implementation, I added a few APIs
to Kconfiglib that turned out to be handy. ``pymenuconfig`` predates
``menuconfig.py`` and ``guiconfig.py``, and so didn't have them available.
Blame me for any workarounds.
Examples
--------
Example scripts
~~~~~~~~~~~~~~~
The `examples/ <https://github.com/ulfalizer/Kconfiglib/blob/master/examples>`_ directory contains some simple example scripts. Among these are the following ones. Make sure you run them with the latest version of Kconfiglib, as they might make use of newly added features.
- `eval_expr.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/eval_expr.py>`_ evaluates an expression in the context of a configuration.
- `find_symbol.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/find_symbol.py>`_ searches through expressions to find references to a symbol, also printing a "backtrace" with parents for each reference found.
- `help_grep.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/help_grep.py>`_ searches for a string in all help texts.
- `print_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_tree.py>`_ prints a tree of all configuration items.
- `print_config_tree.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/print_config_tree.py>`_ is similar to ``print_tree.py``, but dumps the tree as it would appear in ``menuconfig``, including values. This can be handy for visually diffing between ``.config`` files and different versions of ``Kconfig`` files.
- `list_undefined.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/list_undefined.py>`_ finds references to symbols that are not defined by any architecture in the Linux kernel.
- `merge_config.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/merge_config.py>`_ merges configuration fragments to produce a complete .config, similarly to ``scripts/kconfig/merge_config.sh`` from the kernel.
- `menuconfig_example.py <https://github.com/ulfalizer/Kconfiglib/blob/master/examples/menuconfig_example.py>`_ implements a configuration interface that uses notation similar to ``make menuconfig``. It's deliberately kept as simple as possible to demonstrate just the core concepts.
Real-world examples
~~~~~~~~~~~~~~~~~~~
- `kconfig.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/scripts/kconfig/kconfig.py>`_
from the `Zephyr <https://www.zephyrproject.org/>`_ project handles
``.config`` and header file generation, also doing configuration fragment
merging
- `genrest.py
<https://github.com/zephyrproject-rtos/zephyr/blob/master/doc/scripts/genrest.py>`_
generates a Kconfig symbol cross-reference, which can be viewed `here
<http://docs.zephyrproject.org/reference/kconfig/index.html>`__
- `CMake and IDE integration
<https://github.com/espressif/esp-idf/tree/master/tools/kconfig_new>`_ from
the ESP-IDF project, via a configuration server program.
- `A script for turning on USB-related options
<https://github.com/google/syzkaller/blob/master/dashboard/config/kconfiglib-merge-usb-configs.py>`_,
from the `syzkaller <https://github.com/google/syzkaller>`_ project.
- `Various automated checks
<https://github.com/zephyrproject-rtos/ci-tools/blob/master/scripts/check_compliance.py>`_,
including a check for references to undefined Kconfig symbols in source code.
See the ``KconfigCheck`` class.
- `Various utilities
<https://github.com/projectacrn/acrn-hypervisor/tree/master/scripts/kconfig>`_
from the `ACRN <https://projectacrn.org/>`_ project
These use the older Kconfiglib 1 API, which was clunkier and not as general
(functions instead of properties, no direct access to the menu structure or
properties, uglier ``__str__()`` output):
- `genboardscfg.py <http://git.denx.de/?p=u-boot.git;a=blob;f=tools/genboardscfg.py;hb=HEAD>`_ from `Das U-Boot <http://www.denx.de/wiki/U-Boot>`_ generates some sort of legacy board database by pulling information from a newly added Kconfig-based configuration system (as far as I understand it :).
- `gen-manual-lists.py <https://git.busybox.net/buildroot/tree/support/scripts/gen-manual-lists.py?id=5676a2deea896f38123b99781da0a612865adeb0>`_ generated listings for an appendix in the `Buildroot <https://buildroot.org>`_ manual. (The listing has since been removed.)
- `gen_kconfig_doc.py <https://github.com/espressif/esp-idf/blob/master/docs/gen-kconfig-doc.py>`_ from the `esp-idf <https://github.com/espressif/esp-idf>`_ project generates documentation from Kconfig files.
- `SConf <https://github.com/CoryXie/SConf>`_ builds an interactive configuration interface (like ``menuconfig``) on top of Kconfiglib, for use e.g. with `SCons <scons.org>`_.
- `kconfig-diff.py <https://gist.github.com/dubiousjim/5638961>`_ -- a script by `dubiousjim <https://github.com/dubiousjim>`_ that compares kernel configurations.
- Originally, Kconfiglib was used in chapter 4 of my `master's thesis <http://liu.diva-portal.org/smash/get/diva2:473038/FULLTEXT01.pdf>`_ to automatically generate a "minimal" kernel for a given system. Parts of it bother me a bit now, but that's how it goes with old work.
Sample ``make iscriptconfig`` session
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following log should give some idea of the functionality available in the API:
.. code-block::
$ make iscriptconfig
A Kconfig instance 'kconf' for the architecture x86 has been created.
>>> kconf # Calls Kconfig.__repr__()
<configuration with 13711 symbols, main menu prompt "Linux/x86 4.14.0-rc7 Kernel Configuration", srctree ".", config symbol prefix "CONFIG_", warnings enabled, undef. symbol assignment warnings disabled>
>>> kconf.mainmenu_text # Expanded main menu text
'Linux/x86 4.14.0-rc7 Kernel Configuration'
>>> kconf.top_node # The implicit top-level menu
<menu node for menu, prompt "Linux/x86 4.14.0-rc7 Kernel Configuration" (visibility y), deps y, 'visible if' deps y, has child, Kconfig:5>
>>> kconf.top_node.list # First child menu node
<menu node for symbol SRCARCH, deps y, has next, Kconfig:7>
>>> print(kconf.top_node.list) # Calls MenuNode.__str__()
config SRCARCH
string
option env="SRCARCH"
default "x86"
>>> sym = kconf.top_node.list.next.item # Item contained in next menu node
>>> print(sym) # Calls Symbol.__str__()
config 64BIT
bool "64-bit kernel" if ARCH = "x86"
default ARCH != "i386"
help
Say yes to build a 64-bit kernel - formerly known as x86_64
Say no to build a 32-bit kernel - formerly known as i386
>>> sym # Calls Symbol.__repr__()
<symbol 64BIT, bool, "64-bit kernel", value y, visibility y, direct deps y, arch/x86/Kconfig:2>
>>> sym.assignable # Currently assignable values (0, 1, 2 = n, m, y)
(0, 2)
>>> sym.set_value(0) # Set it to n
True
>>> sym.tri_value # Check the new value
0
>>> sym = kconf.syms["X86_MPPARSE"] # Look up symbol by name
>>> print(sym)
config X86_MPPARSE
bool "Enable MPS table" if (ACPI || SFI) && X86_LOCAL_APIC
default y if X86_LOCAL_APIC
help
For old smp systems that do not have proper acpi support. Newer systems
(esp with 64bit cpus) with acpi support, MADT and DSDT will override it
>>> default = sym.defaults[0] # Fetch its first default
>>> sym = default[1] # Fetch the default's condition (just a Symbol here)
>>> print(sym)
config X86_LOCAL_APIC
bool
default y
select IRQ_DOMAIN_HIERARCHY
select PCI_MSI_IRQ_DOMAIN if PCI_MSI
depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI
>>> sym.nodes # Show the MenuNode(s) associated with it
[<menu node for symbol X86_LOCAL_APIC, deps n, has next, arch/x86/Kconfig:1015>]
>>> kconfiglib.expr_str(sym.defaults[0][1]) # Print the default's condition
'X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_APIC || PCI_MSI'
>>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it (0 = n)
0
>>> kconf.syms["64BIT"].set_value(2)
True
>>> kconfiglib.expr_value(sym.defaults[0][1]) # Evaluate it again (2 = y)
2
>>> kconf.write_config("myconfig") # Save a .config
>>> ^D
$ cat myconfig
# Generated by Kconfiglib (https://github.com/ulfalizer/Kconfiglib)
CONFIG_64BIT=y
CONFIG_X86_64=y
CONFIG_X86=y
CONFIG_INSTRUCTION_DECODER=y
CONFIG_OUTPUT_FORMAT="elf64-x86-64"
CONFIG_ARCH_DEFCONFIG="arch/x86/configs/x86_64_defconfig"
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_STACKTRACE_SUPPORT=y
CONFIG_MMU=y
...
Test suite
----------
The test suite is run with
.. code::
$ python(3) Kconfiglib/testsuite.py
`pypy <https://pypy.org/>`_ works too, and is much speedier for everything except ``allnoconfig.py``/``allnoconfig_simpler.py``/``allyesconfig.py``, where it doesn't have time to warm up since
the scripts are run via ``make scriptconfig``.
The test suite must be run from the top-level kernel directory. It requires that the
Kconfiglib git repository has been cloned into it and that the makefile patch has been applied.
To get rid of warnings generated for the kernel ``Kconfig`` files, add ``2>/dev/null`` to the command to
discard ``stderr``.
**NOTE: Forgetting to apply the Makefile patch will cause some tests that compare generated configurations to fail**
**NOTE: The test suite overwrites .config in the kernel root, so make sure to back it up.**
The test suite consists of a set of selftests and a set of compatibility tests that
compare configurations generated by Kconfiglib with
configurations generated by the C tools, for a number of cases. See
`testsuite.py <https://github.com/ulfalizer/Kconfiglib/blob/master/testsuite.py>`_
for the available options.
The `tests/reltest <https://github.com/ulfalizer/Kconfiglib/blob/master/tests/reltest>`_ script runs the test suite
and all the example scripts for both Python 2 and Python 3, verifying that everything works.
Rarely, the output from the C tools is changed slightly (most recently due to a
`change <https://www.spinics.net/lists/linux-kbuild/msg17074.html>`_ I added).
If you get test suite failures, try running the test suite again against the
`linux-next tree <https://www.kernel.org/doc/man-pages/linux-next.html>`_,
which has all the latest changes. I will make it clear if any
non-backwards-compatible changes appear.
A lot of time is spent waiting around for ``make`` and the C utilities (which need to reparse all the
Kconfig files for each defconfig test). Adding some multiprocessing to the test suite would make sense
too.
Notes
-----
* This is version 2 of Kconfiglib, which is not backwards-compatible with
Kconfiglib 1. A summary of changes between Kconfiglib 1 and Kconfiglib
2 can be found `here
<https://github.com/ulfalizer/Kconfiglib/blob/screenshots/kconfiglib-2-changes.txt>`__.
* I sometimes see people add custom output formats, which is pretty
straightforward to do (see the implementations of ``write_autoconf()`` and
``write_config()`` for a template, and also the documentation of the
``Symbol.config_string`` property). If you come up with something you think
might be useful to other people, I'm happy to take it in upstream. Batteries
included and all that.
* Kconfiglib assumes the modules symbol is ``MODULES``, which is backwards-compatible.
A warning is printed by default if ``option modules`` is set on some other symbol.
Let me know if you need proper ``option modules`` support. It wouldn't be that
hard to add.
Thanks
------
- To `RomaVis <https://github.com/RomaVis>`_, for making
`pymenuconfig <https://github.com/RomaVis/pymenuconfig>`_ and suggesting
the ``rsource`` keyword.
- To `Mitja Horvat <https://github.com/pinkfluid>`_, for adding support
for user-defined styles to the terminal menuconfig.
- To `Philip Craig <https://github.com/philipc>`_ for adding
support for the ``allnoconfig_y`` option and fixing an obscure issue
with ``comment``\s inside ``choice``\s (that didn't affect correctness but
made outputs differ). ``allnoconfig_y`` is used to force certain symbols
to ``y`` during ``make allnoconfig`` to improve coverage.
License
-------
See `LICENSE.txt <https://github.com/ulfalizer/Kconfiglib/blob/master/LICENSE.txt>`_. SPDX license identifiers are used in the
source code.

View File

@@ -0,0 +1,27 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where all symbols are set to their their default
values.
The default output filename is '.config'. A different filename can be passed in
the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/alldefconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
kconf.load_allconfig("alldef.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,46 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'm'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allmodconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
for sym in kconf.unique_defined_syms:
if sym.orig_type == kconfiglib.BOOL:
# 'bool' choice symbols get their default value, as determined by
# e.g. 'default's on the choice
if not sym.choice:
# All other bool symbols get set to 'y', like for allyesconfig
sym.set_value(2)
elif sym.orig_type == kconfiglib.TRISTATE:
sym.set_value(1)
for choice in kconf.unique_choices:
choice.set_value(2 if choice.orig_type == kconfiglib.BOOL else 1)
kconf.warn = True
kconf.load_allconfig("allmod.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'n'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allnoconfig.py
"""
# See examples/allnoconfig_walk.py for another way to implement this script
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# Avoid warnings that would otherwise get printed by Kconfiglib for the
# following:
#
# 1. Assigning a value to a symbol without a prompt, which never has any
# effect
#
# 2. Assigning values invalid for the type (only bool/tristate symbols
# accept 0/1/2, for n/m/y). The assignments will be ignored for other
# symbol types, which is what we want.
kconf.warn = False
for sym in kconf.unique_defined_syms:
sym.set_value(2 if sym.is_allnoconfig_y else 0)
kconf.warn = True
kconf.load_allconfig("allno.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Writes a configuration file where as many symbols as possible are set to 'y'.
The default output filename is '.config'. A different filename can be passed
in the KCONFIG_CONFIG environment variable.
Usage for the Linux kernel:
$ make [ARCH=<arch>] scriptconfig SCRIPT=Kconfiglib/allyesconfig.py
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
# See allnoconfig.py
kconf.warn = False
# Try to set all symbols to 'y'. Dependencies might truncate the value down
# later, but this will at least give the highest possible value.
#
# Assigning 0/1/2 to non-bool/tristate symbols has no effect (int/hex
# symbols still take a string, because they preserve formatting).
for sym in kconf.unique_defined_syms:
# Set choice symbols to 'm'. This value will be ignored for choices in
# 'y' mode (the "normal" mode), which will instead just get their
# default selection, but will set all symbols in m-mode choices to 'm',
# which is as high as they can go.
#
# Here's a convoluted example of how you might get an m-mode choice
# even during allyesconfig:
#
# choice
# tristate "weird choice"
# depends on m
sym.set_value(1 if sym.choice else 2)
# Set all choices to the highest possible mode
for choice in kconf.unique_choices:
choice.set_value(2)
kconf.warn = True
kconf.load_allconfig("allyes.config")
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,43 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Reads a specified configuration file, then writes a new configuration file.
This can be used to initialize the configuration from e.g. an arch-specific
configuration file. This input configuration file would usually be a minimal
configuration file, as generated by e.g. savedefconfig.
The default output filename is '.config'. A different filename can be passed in
the KCONFIG_CONFIG environment variable.
"""
import argparse
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"config",
metavar="CONFIGURATION",
help="Input configuration file")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config(args.config))
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Generates a header file with #defines from the configuration, matching the
format of include/generated/autoconf.h in the Linux kernel.
Optionally, also writes the configuration output as a .config file. See
--config-out.
The --sync-deps, --file-list, and --env-list options generate information that
can be used to avoid needless rebuilds/reconfigurations.
Before writing a header or configuration file, Kconfiglib compares the old
contents of the file against the new contents. If there's no change, the write
is skipped. This avoids updating file metadata like the modification time, and
might save work depending on your build setup.
By default, the configuration is generated from '.config'. A different
configuration file can be passed in the KCONFIG_CONFIG environment variable.
A custom header string can be inserted at the beginning of generated
configuration and header files by setting the KCONFIG_CONFIG_HEADER and
KCONFIG_AUTOHEADER_HEADER environment variables, respectively (this also works
for other scripts). The string is not automatically made a comment (this is by
design, to allow anything to be added), and no trailing newline is added, so
add '/* */', '#', and newlines as appropriate.
See https://www.gnu.org/software/make/manual/make.html#Multi_002dLine for a
handy way to define multi-line variables in makefiles, for use with custom
headers. Remember to export the variable to the environment.
"""
import argparse
import os
import sys
import kconfiglib
DEFAULT_SYNC_DEPS_PATH = "deps/"
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--header-path",
metavar="HEADER_FILE",
help="""
Path to write the generated header file to. If not specified, the path in the
environment variable KCONFIG_AUTOHEADER is used if it is set, and 'config.h'
otherwise.
""")
parser.add_argument(
"--config-out",
metavar="CONFIG_FILE",
help="""
Write the configuration to CONFIG_FILE. This is useful if you include .config
files in Makefiles, as the generated configuration file will be a full .config
file even if .config is outdated. The generated configuration matches what
olddefconfig would produce. If you use sync-deps, you can include
deps/auto.conf instead. --config-out is meant for cases where incremental build
information isn't needed.
""")
parser.add_argument(
"--sync-deps",
metavar="OUTPUT_DIR",
nargs="?",
const=DEFAULT_SYNC_DEPS_PATH,
help="""
Enable generation of symbol dependency information for incremental builds,
optionally specifying the output directory (default: {}). See the docstring of
Kconfig.sync_deps() in Kconfiglib for more information.
""".format(DEFAULT_SYNC_DEPS_PATH))
parser.add_argument(
"--file-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all Kconfig files to OUTPUT_FILE, with one file per line. The
paths are relative to $srctree (or to the current directory if $srctree is
unset). Files appear in the order they're 'source'd.
""")
parser.add_argument(
"--env-list",
metavar="OUTPUT_FILE",
help="""
Write a list of all environment variables referenced in Kconfig files to
OUTPUT_FILE, with one variable per line. Each line has the format NAME=VALUE.
Only environment variables referenced with the preprocessor $(VAR) syntax are
included, and not variables referenced with the older $VAR syntax (which is
only supported for backwards compatibility).
""")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
kconf.load_config()
if args.header_path is None:
if "KCONFIG_AUTOHEADER" in os.environ:
kconf.write_autoconf()
else:
# Kconfiglib defaults to include/generated/autoconf.h to be
# compatible with the C tools. 'config.h' is used here instead for
# backwards compatibility. It's probably a saner default for tools
# as well.
kconf.write_autoconf("config.h")
else:
kconf.write_autoconf(args.header_path)
if args.config_out is not None:
kconf.write_config(args.config_out, save_old=False)
if args.sync_deps is not None:
kconf.sync_deps(args.sync_deps)
if args.file_list is not None:
with _open_write(args.file_list) as f:
for path in kconf.kconfig_filenames:
f.write(path + "\n")
if args.env_list is not None:
with _open_write(args.env_list) as f:
for env_var in kconf.env_vars:
f.write("{}={}\n".format(env_var, os.environ[env_var]))
def _open_write(path):
# Python 2/3 compatibility. io.open() is available on both, but makes
# write() expect 'unicode' strings on Python 2.
if sys.version_info[0] < 3:
return open(path, "w")
return open(path, "w", encoding="utf-8")
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,76 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Lists all user-modifiable symbols that are not given a value in the
configuration file. Usually, these are new symbols that have been added to the
Kconfig files.
The default configuration filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
"""
from __future__ import print_function
import argparse
import sys
from kconfiglib import Kconfig, BOOL, TRISTATE, INT, HEX, STRING, TRI_TO_STR
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--show-help", "-l",
action="store_true",
help="Show any help texts as well")
parser.add_argument(
"kconfig",
metavar="KCONFIG",
nargs="?",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
args = parser.parse_args()
kconf = Kconfig(args.kconfig, suppress_traceback=True)
# Make it possible to filter this message out
print(kconf.load_config(), file=sys.stderr)
for sym in kconf.unique_defined_syms:
# Only show symbols that can be toggled. Choice symbols are a special
# case in that sym.assignable will be (2,) (length 1) for visible
# symbols in choices in y mode, but they can still be toggled by
# selecting some other symbol.
if sym.user_value is None and \
(len(sym.assignable) > 1 or
(sym.visibility and (sym.orig_type in (INT, HEX, STRING) or
sym.choice))):
# Don't reuse the 'config_string' format for bool/tristate symbols,
# to show n-valued symbols as 'CONFIG_FOO=n' instead of
# '# CONFIG_FOO is not set'. This matches the C tools.
if sym.orig_type in (BOOL, TRISTATE):
s = "{}{}={}\n".format(kconf.config_prefix, sym.name,
TRI_TO_STR[sym.tri_value])
else:
s = sym.config_string
print(s, end="")
if args.show_help:
for node in sym.nodes:
if node.help is not None:
# Indent by two spaces. textwrap.indent() is not
# available in Python 2 (it's 3.3+).
print("\n".join(" " + line
for line in node.help.split("\n")))
break
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,246 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Implements oldconfig functionality.
1. Loads existing .config
2. Prompts for the value of all modifiable symbols/choices that
aren't already set in the .config
3. Writes an updated .config
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
Entering '?' displays the help text of the symbol/choice, if any.
Unlike 'make oldconfig', this script doesn't print menu titles and comments,
but gives Kconfig definition locations. Printing menus and comments would be
pretty easy to add: Look at the parents of each item, and print all menu
prompts and comments unless they have already been printed (assuming you want
to skip "irrelevant" menus).
"""
from __future__ import print_function
import sys
from kconfiglib import Symbol, Choice, BOOL, TRISTATE, HEX, standard_kconfig
# Python 2/3 compatibility hack
if sys.version_info[0] < 3:
input = raw_input
def _main():
# Earlier symbols in Kconfig files might depend on later symbols and become
# visible if their values change. This flag is set to True if the value of
# any symbol changes, in which case we rerun the oldconfig to check for new
# visible symbols.
global conf_changed
kconf = standard_kconfig(__doc__)
print(kconf.load_config())
while True:
conf_changed = False
for node in kconf.node_iter():
oldconfig(node)
if not conf_changed:
break
print(kconf.write_config())
def oldconfig(node):
"""
Prompts the user for a value if node.item is a visible symbol/choice with
no user value.
"""
# See main()
global conf_changed
# Only symbols and choices can be configured
if not isinstance(node.item, (Symbol, Choice)):
return
# Skip symbols and choices that aren't visible
if not node.item.visibility:
return
# Skip symbols and choices that don't have a prompt (at this location)
if not node.prompt:
return
if isinstance(node.item, Symbol):
sym = node.item
# Skip symbols that already have a user value
if sym.user_value is not None:
return
# Skip symbols that can only have a single value, due to selects
if len(sym.assignable) == 1:
return
# Skip symbols in choices in y mode. We ask once for the entire choice
# instead.
if sym.choice and sym.choice.tri_value == 2:
return
# Loop until the user enters a valid value or enters a blank string
# (for the default value)
while True:
val = input("{} ({}) [{}] ".format(
node.prompt[0], _name_and_loc_str(sym),
_default_value_str(sym)))
if val == "?":
_print_help(node)
continue
# Substitute a blank string with the default value the symbol
# would get
if not val:
val = sym.str_value
# Automatically add a "0x" prefix for hex symbols, like the
# menuconfig interface does. This isn't done when loading .config
# files, hence why set_value() doesn't do it automatically.
if sym.type == HEX and not val.startswith(("0x", "0X")):
val = "0x" + val
old_str_val = sym.str_value
# Kconfiglib itself will print a warning here if the value
# is invalid, so we don't need to bother
if sym.set_value(val):
# Valid value input. We're done with this node.
if sym.str_value != old_str_val:
conf_changed = True
return
else:
choice = node.item
# Skip choices that already have a visible user selection...
if choice.user_selection and choice.user_selection.visibility == 2:
# ...unless there are new visible symbols in the choice. (We know
# they have y (2) visibility in that case, because m-visible
# symbols get demoted to n-visibility in y-mode choices, and the
# user-selected symbol had visibility y.)
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility and \
sym.user_value is None:
# New visible symbols in the choice
break
else:
# No new visible symbols in the choice
return
# Get a list of available selections. The mode of the choice limits
# the visibility of the choice value symbols, so this will indirectly
# skip choices in n and m mode.
options = [sym for sym in choice.syms if sym.visibility == 2]
if not options:
# No y-visible choice value symbols
return
# Loop until the user enters a valid selection or a blank string (for
# the default selection)
while True:
print("{} ({})".format(node.prompt[0], _name_and_loc_str(choice)))
for i, sym in enumerate(options, 1):
print("{} {}. {} ({})".format(
">" if sym is choice.selection else " ",
i,
# Assume people don't define choice symbols with multiple
# prompts. That generates a warning anyway.
sym.nodes[0].prompt[0],
sym.name))
sel_index = input("choice[1-{}]: ".format(len(options)))
if sel_index == "?":
_print_help(node)
continue
# Pick the default selection if the string is blank
if not sel_index:
choice.selection.set_value(2)
break
try:
sel_index = int(sel_index)
except ValueError:
print("Bad index", file=sys.stderr)
continue
if not 1 <= sel_index <= len(options):
print("Bad index", file=sys.stderr)
continue
# Valid selection
if options[sel_index - 1].tri_value != 2:
conf_changed = True
options[sel_index - 1].set_value(2)
break
# Give all of the non-selected visible choice symbols the user value n.
# This makes it so that the choice is no longer considered new once we
# do additional passes, if the reason that it was considered new was
# that it had new visible choice symbols.
#
# Only giving visible choice symbols the user value n means we will
# prompt for the choice again if later user selections make more new
# choice symbols visible, which is correct.
for sym in choice.syms:
if sym is not choice.user_selection and sym.visibility:
sym.set_value(0)
def _name_and_loc_str(sc):
# Helper for printing the name of the symbol/choice 'sc' along with the
# location(s) in the Kconfig files where it is defined. Unnamed choices
# return "choice" instead of the name.
return "{}, defined at {}".format(
sc.name or "choice",
", ".join("{}:{}".format(node.filename, node.linenr)
for node in sc.nodes))
def _print_help(node):
print("\n" + (node.help or "No help text\n"))
def _default_value_str(sym):
# Returns the "m/M/y" string in e.g.
#
# TRISTATE_SYM prompt (TRISTATE_SYM, defined at Kconfig:9) [n/M/y]:
#
# For string/int/hex, returns the default value as-is.
if sym.type in (BOOL, TRISTATE):
return "/".join(("NMY" if sym.tri_value == tri else "nmy")[tri]
for tri in sym.assignable)
# string/int/hex
return sym.str_value
if __name__ == "__main__":
_main()

View File

@@ -0,0 +1,28 @@
#!/usr/bin/env python3
# Copyright (c) 2018-2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Updates an old .config file or creates a new one, by filling in default values
for all new symbols. This is the same as picking the default selection for all
symbols in oldconfig, or entering the menuconfig interface and immediately
saving.
The default input/output filename is '.config'. A different filename can be
passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import kconfiglib
def main():
kconf = kconfiglib.standard_kconfig(__doc__)
print(kconf.load_config())
print(kconf.write_config())
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Saves a minimal configuration file that only lists symbols that differ in value
from their defaults. Loading such a configuration file is equivalent to loading
the "full" configuration file.
Minimal configuration files are handy to start from when editing configuration
files by hand.
The default input configuration file is '.config'. A different input filename
can be passed in the KCONFIG_CONFIG environment variable.
Note: Minimal configurations can also be generated from within the menuconfig
interface.
"""
import argparse
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--out",
metavar="MINIMAL_CONFIGURATION",
default="defconfig",
help="Output filename for minimal configuration (default: defconfig)")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
print(kconf.write_min_config(args.out))
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,92 @@
#!/usr/bin/env python3
# Copyright (c) 2019, Ulf Magnusson
# SPDX-License-Identifier: ISC
"""
Simple utility for setting configuration values from the command line.
Sample usage:
$ setconfig FOO_SUPPORT=y BAR_BITS=8
Note: Symbol names should not be prefixed with 'CONFIG_'.
The exit status on errors is 1.
The default input/output configuration file is '.config'. A different filename
can be passed in the KCONFIG_CONFIG environment variable.
When overwriting a configuration file, the old version is saved to
<filename>.old (e.g. .config.old).
"""
import argparse
import sys
import kconfiglib
def main():
parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description=__doc__)
parser.add_argument(
"--kconfig",
default="Kconfig",
help="Top-level Kconfig file (default: Kconfig)")
parser.add_argument(
"--no-check-exists",
dest="check_exists",
action="store_false",
help="Ignore assignments to non-existent symbols instead of erroring "
"out")
parser.add_argument(
"--no-check-value",
dest="check_value",
action="store_false",
help="Ignore assignments that didn't \"take\" (where the symbol got a "
"different value, e.g. due to unsatisfied dependencies) instead "
"of erroring out")
parser.add_argument(
"assignments",
metavar="ASSIGNMENT",
nargs="*",
help="A 'NAME=value' assignment")
args = parser.parse_args()
kconf = kconfiglib.Kconfig(args.kconfig, suppress_traceback=True)
print(kconf.load_config())
for arg in args.assignments:
if "=" not in arg:
sys.exit("error: no '=' in assignment: '{}'".format(arg))
name, value = arg.split("=", 1)
if name not in kconf.syms:
if not args.check_exists:
continue
sys.exit("error: no symbol '{}' in configuration".format(name))
sym = kconf.syms[name]
if not sym.set_value(value):
sys.exit("error: '{}' is an invalid value for the {} symbol {}"
.format(value, kconfiglib.TYPE_TO_STR[sym.orig_type],
name))
if args.check_value and sym.str_value != value:
sys.exit("error: {} was assigned the value '{}', but got the "
"value '{}'. Check the symbol's dependencies, and make "
"sure that it has a prompt."
.format(name, value, sym.str_value))
print(kconf.write_config())
if __name__ == "__main__":
main()

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "../bl1_private.h"
/*******************************************************************************
* TODO: Function that does the first bit of architectural setup.
******************************************************************************/
void bl1_arch_setup(void)
{
}

View File

@@ -0,0 +1,172 @@
/*
* Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <context.h>
#include <common/debug.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <plat/common/platform.h>
#include <smccc_helpers.h>
#include "../bl1_private.h"
/*
* Following arrays will be used for context management.
* There are 2 instances, for the Secure and Non-Secure contexts.
*/
static cpu_context_t bl1_cpu_context[2];
static smc_ctx_t bl1_smc_context[2];
/* Following contains the next cpu context pointer. */
static void *bl1_next_cpu_context_ptr;
/* Following contains the next smc context pointer. */
static void *bl1_next_smc_context_ptr;
/* Following functions are used for SMC context handling */
void *smc_get_ctx(unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
return &bl1_smc_context[security_state];
}
void smc_set_next_ctx(unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
bl1_next_smc_context_ptr = &bl1_smc_context[security_state];
}
void *smc_get_next_ctx(void)
{
return bl1_next_smc_context_ptr;
}
/* Following functions are used for CPU context handling */
void *cm_get_context(uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
return &bl1_cpu_context[security_state];
}
void cm_set_next_context(void *context)
{
assert(context != NULL);
bl1_next_cpu_context_ptr = context;
}
void *cm_get_next_context(void)
{
return bl1_next_cpu_context_ptr;
}
/*******************************************************************************
* Following function copies GP regs r0-r4, lr and spsr,
* from the CPU context to the SMC context structures.
******************************************************************************/
static void copy_cpu_ctx_to_smc_ctx(const regs_t *cpu_reg_ctx,
smc_ctx_t *next_smc_ctx)
{
next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1);
next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2);
next_smc_ctx->r3 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R3);
next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
}
/*******************************************************************************
* Following function flushes the SMC & CPU context pointer and its data.
******************************************************************************/
static void flush_smc_and_cpu_ctx(void)
{
flush_dcache_range((uintptr_t)&bl1_next_smc_context_ptr,
sizeof(bl1_next_smc_context_ptr));
flush_dcache_range((uintptr_t)bl1_next_smc_context_ptr,
sizeof(smc_ctx_t));
flush_dcache_range((uintptr_t)&bl1_next_cpu_context_ptr,
sizeof(bl1_next_cpu_context_ptr));
flush_dcache_range((uintptr_t)bl1_next_cpu_context_ptr,
sizeof(cpu_context_t));
}
/*******************************************************************************
* This function prepares the context for Secure/Normal world images.
* Normal world images are transitioned to HYP(if supported) else SVC.
******************************************************************************/
void bl1_prepare_next_image(unsigned int image_id)
{
unsigned int security_state, mode = MODE32_svc;
image_desc_t *desc;
entry_point_info_t *next_bl_ep;
/* Get the image descriptor. */
desc = bl1_plat_get_image_desc(image_id);
assert(desc != NULL);
/* Get the entry point info. */
next_bl_ep = &desc->ep_info;
/* Get the image security state. */
security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);
/* Prepare the SPSR for the next BL image. */
if ((security_state != SECURE) && (GET_VIRT_EXT(read_id_pfr1()) != 0U)) {
mode = MODE32_hyp;
}
next_bl_ep->spsr = SPSR_MODE32(mode, SPSR_T_ARM,
SPSR_E_LITTLE, DISABLE_ALL_EXCEPTIONS);
/* Allow platform to make change */
bl1_plat_set_ep_info(image_id, next_bl_ep);
/* Prepare the cpu context for the next BL image. */
cm_init_my_context(next_bl_ep);
cm_prepare_el3_exit(security_state);
cm_set_next_context(cm_get_context(security_state));
/* Prepare the smc context for the next BL image. */
smc_set_next_ctx(security_state);
copy_cpu_ctx_to_smc_ctx(get_regs_ctx(cm_get_next_context()),
smc_get_next_ctx());
/*
* If the next image is non-secure, then we need to program the banked
* non secure sctlr. This is not required when the next image is secure
* because in AArch32, we expect the secure world to have the same
* SCTLR settings.
*/
if (security_state == NON_SECURE) {
cpu_context_t *ctx = cm_get_context(security_state);
u_register_t ns_sctlr;
/* Temporarily set the NS bit to access NS SCTLR */
write_scr(read_scr() | SCR_NS_BIT);
isb();
ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
write_sctlr(ns_sctlr);
isb();
write_scr(read_scr() & ~SCR_NS_BIT);
isb();
}
/*
* Flush the SMC & CPU context and the (next)pointers,
* to access them after caches are disabled.
*/
flush_smc_and_cpu_ctx();
/* Indicate that image is in execution state. */
desc->state = IMAGE_STATE_EXECUTED;
print_entry_point_info(next_bl_ep);
}

View File

@@ -0,0 +1,99 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <context.h>
#include <el3_common_macros.S>
#include <smccc_helpers.h>
#include <smccc_macros.S>
.globl bl1_vector_table
.globl bl1_entrypoint
/* -----------------------------------------------------
* Setup the vector table to support SVC & MON mode.
* -----------------------------------------------------
*/
vector_base bl1_vector_table
b bl1_entrypoint
b report_exception /* Undef */
b bl1_aarch32_smc_handler /* SMC call */
b report_exception /* Prefetch abort */
b report_exception /* Data abort */
b report_exception /* Reserved */
b report_exception /* IRQ */
b report_exception /* FIQ */
/* -----------------------------------------------------
* bl1_entrypoint() is the entry point into the trusted
* firmware code when a cpu is released from warm or
* cold reset.
* -----------------------------------------------------
*/
func bl1_entrypoint
/* ---------------------------------------------------------------------
* If the reset address is programmable then bl1_entrypoint() is
* executed only on the cold boot path. Therefore, we can skip the warm
* boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=bl1_vector_table \
_pie_fixup_size=0
/* -----------------------------------------------------
* Perform BL1 setup
* -----------------------------------------------------
*/
bl bl1_setup
/* -----------------------------------------------------
* Jump to main function.
* -----------------------------------------------------
*/
bl bl1_main
/* -----------------------------------------------------
* Jump to next image.
* -----------------------------------------------------
*/
/*
* Get the smc_context for next BL image,
* program the gp/system registers and save it in `r4`.
*/
bl smc_get_next_ctx
mov r4, r0
/* Only turn-off MMU if going to secure world */
ldr r5, [r4, #SMC_CTX_SCR]
tst r5, #SCR_NS_BIT
bne skip_mmu_off
/*
* MMU needs to be disabled because both BL1 and BL2/BL2U execute
* in PL1, and therefore share the same address space.
* BL2/BL2U will initialize the address space according to its
* own requirement.
*/
bl disable_mmu_icache_secure
stcopr r0, TLBIALL
dsb sy
isb
skip_mmu_off:
/* Restore smc_context from `r4` and exit secure monitor mode. */
mov r0, r4
monitor_exit
endfunc bl1_entrypoint

View File

@@ -0,0 +1,165 @@
/*
* Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <context.h>
#include <lib/xlat_tables/xlat_tables.h>
#include <smccc_helpers.h>
#include <smccc_macros.S>
.globl bl1_aarch32_smc_handler
func bl1_aarch32_smc_handler
/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
str lr, [sp, #SMC_CTX_LR_MON]
/* ------------------------------------------------
* SMC in BL1 is handled assuming that the MMU is
* turned off by BL2.
* ------------------------------------------------
*/
/* ----------------------------------------------
* Detect if this is a RUN_IMAGE or other SMC.
* ----------------------------------------------
*/
mov lr, #BL1_SMC_RUN_IMAGE
cmp lr, r0
bne smc_handler
/* ------------------------------------------------
* Make sure only Secure world reaches here.
* ------------------------------------------------
*/
ldcopr r8, SCR
tst r8, #SCR_NS_BIT
blne report_exception
/* ---------------------------------------------------------------------
* Pass control to next secure image.
* Here it expects r1 to contain the address of a entry_point_info_t
* structure describing the BL entrypoint.
* ---------------------------------------------------------------------
*/
mov r8, r1
mov r0, r1
bl bl1_print_next_bl_ep_info
#if SPIN_ON_BL1_EXIT
bl print_debug_loop_message
debug_loop:
b debug_loop
#endif
mov r0, r8
bl bl1_plat_prepare_exit
stcopr r0, TLBIALL
dsb sy
isb
/*
* Extract PC and SPSR based on struct `entry_point_info_t`
* and load it in LR and SPSR registers respectively.
*/
ldr lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
ldr r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
msr spsr_xc, r1
/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
cps #MODE32_svc
ldr lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
cps #MODE32_mon
add r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
ldm r8, {r0, r1, r2, r3}
exception_return
endfunc bl1_aarch32_smc_handler
/* -----------------------------------------------------
* Save Secure/Normal world context and jump to
* BL1 SMC handler.
* -----------------------------------------------------
*/
func smc_handler
/* -----------------------------------------------------
* Save the GP registers.
* -----------------------------------------------------
*/
smccc_save_gp_mode_regs
/*
* `sp` still points to `smc_ctx_t`. Save it to a register
* and restore the C runtime stack pointer to `sp`.
*/
mov r6, sp
ldr sp, [r6, #SMC_CTX_SP_MON]
ldr r0, [r6, #SMC_CTX_SCR]
and r7, r0, #SCR_NS_BIT /* flags */
/* Switch to Secure Mode */
bic r0, #SCR_NS_BIT
stcopr r0, SCR
isb
/* If caller is from Secure world then turn on the MMU */
tst r7, #SCR_NS_BIT
bne skip_mmu_on
/* Turn on the MMU */
mov r0, #DISABLE_DCACHE
bl enable_mmu_svc_mon
/*
* Invalidate `smc_ctx_t` in data cache to prevent dirty data being
* used.
*/
mov r0, r6
mov r1, #SMC_CTX_SIZE
bl inv_dcache_range
/* Enable the data cache. */
ldcopr r9, SCTLR
orr r9, r9, #SCTLR_C_BIT
stcopr r9, SCTLR
isb
skip_mmu_on:
/* Prepare arguments for BL1 SMC wrapper. */
ldr r0, [r6, #SMC_CTX_GPREG_R0] /* smc_fid */
mov r1, #0 /* cookie */
mov r2, r6 /* handle */
mov r3, r7 /* flags */
bl bl1_smc_wrapper
/* Get the smc_context for next BL image */
bl smc_get_next_ctx
mov r4, r0
/* Only turn-off MMU if going to secure world */
ldr r5, [r4, #SMC_CTX_SCR]
tst r5, #SCR_NS_BIT
bne skip_mmu_off
/* Disable the MMU */
bl disable_mmu_icache_secure
stcopr r0, TLBIALL
dsb sy
isb
skip_mmu_off:
/* -----------------------------------------------------
* Do the transition to next BL image.
* -----------------------------------------------------
*/
mov r0, r4
monitor_exit
endfunc smc_handler

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include "../bl1_private.h"
/*******************************************************************************
* Function that does the first bit of architectural setup that affects
* execution in the non-secure address space.
******************************************************************************/
void bl1_arch_setup(void)
{
/* Set the next EL to be AArch64 */
write_scr_el3(read_scr_el3() | SCR_RW_BIT);
}
/*******************************************************************************
* Set the Secure EL1 required architectural state
******************************************************************************/
void bl1_arch_next_el_setup(void)
{
u_register_t next_sctlr;
/* Use the same endianness than the current BL */
next_sctlr = (read_sctlr_el3() & SCTLR_EE_BIT);
/* Set SCTLR Secure EL1 */
next_sctlr |= SCTLR_EL1_RES1;
write_sctlr_el1(next_sctlr);
}

View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2015-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <context.h>
#include <common/debug.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <plat/common/platform.h>
#include "../bl1_private.h"
/* Following contains the cpu context pointers. */
static void *bl1_cpu_context_ptr[2];
entry_point_info_t *bl2_ep_info;
void *cm_get_context(uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
return bl1_cpu_context_ptr[security_state];
}
void cm_set_context(void *context, uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
bl1_cpu_context_ptr[security_state] = context;
}
#if ENABLE_RME
/*******************************************************************************
* This function prepares the entry point information to run BL2 in Root world,
* i.e. EL3, for the case when FEAT_RME is enabled.
******************************************************************************/
void bl1_prepare_next_image(unsigned int image_id)
{
image_desc_t *bl2_desc;
assert(image_id == BL2_IMAGE_ID);
/* Get the image descriptor. */
bl2_desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
assert(bl2_desc != NULL);
/* Get the entry point info. */
bl2_ep_info = &bl2_desc->ep_info;
bl2_ep_info->spsr = (uint32_t)SPSR_64(MODE_EL3, MODE_SP_ELX,
DISABLE_ALL_EXCEPTIONS);
/*
* Flush cache since bl2_ep_info is accessed after MMU is disabled
* before jumping to BL2.
*/
flush_dcache_range((uintptr_t)bl2_ep_info, sizeof(entry_point_info_t));
/* Indicate that image is in execution state. */
bl2_desc->state = IMAGE_STATE_EXECUTED;
/* Print debug info and flush the console before running BL2. */
print_entry_point_info(bl2_ep_info);
}
#else
/*******************************************************************************
* This function prepares the context for Secure/Normal world images.
* Normal world images are transitioned to EL2(if supported) else EL1.
******************************************************************************/
void bl1_prepare_next_image(unsigned int image_id)
{
/*
* Following array will be used for context management.
* There are 2 instances, for the Secure and Non-Secure contexts.
*/
static cpu_context_t bl1_cpu_context[2];
unsigned int security_state, mode = MODE_EL1;
image_desc_t *desc;
entry_point_info_t *next_bl_ep;
#if CTX_INCLUDE_AARCH32_REGS
/*
* Ensure that the build flag to save AArch32 system registers in CPU
* context is not set for AArch64-only platforms.
*/
if (el_implemented(1) == EL_IMPL_A64ONLY) {
ERROR("EL1 supports AArch64-only. Please set build flag "
"CTX_INCLUDE_AARCH32_REGS = 0\n");
panic();
}
#endif
/* Get the image descriptor. */
desc = bl1_plat_get_image_desc(image_id);
assert(desc != NULL);
/* Get the entry point info. */
next_bl_ep = &desc->ep_info;
/* Get the image security state. */
security_state = GET_SECURITY_STATE(next_bl_ep->h.attr);
/* Setup the Secure/Non-Secure context if not done already. */
if (cm_get_context(security_state) == NULL)
cm_set_context(&bl1_cpu_context[security_state], security_state);
/* Prepare the SPSR for the next BL image. */
if ((security_state != SECURE) && (el_implemented(2) != EL_IMPL_NONE)) {
mode = MODE_EL2;
}
next_bl_ep->spsr = (uint32_t)SPSR_64((uint64_t) mode,
(uint64_t)MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS);
/* Allow platform to make change */
bl1_plat_set_ep_info(image_id, next_bl_ep);
/* Prepare the context for the next BL image. */
cm_init_my_context(next_bl_ep);
cm_prepare_el3_exit(security_state);
/* Indicate that image is in execution state. */
desc->state = IMAGE_STATE_EXECUTED;
print_entry_point_info(next_bl_ep);
}
#endif /* ENABLE_RME */

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <common/bl_common.h>
#include <el3_common_macros.S>
.globl bl1_entrypoint
.globl bl1_run_bl2_in_root
/* -----------------------------------------------------
* bl1_entrypoint() is the entry point into the trusted
* firmware code when a cpu is released from warm or
* cold reset.
* -----------------------------------------------------
*/
func bl1_entrypoint
/* ---------------------------------------------------------------------
* If the reset address is programmable then bl1_entrypoint() is
* executed only on the cold boot path. Therefore, we can skip the warm
* boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=bl1_exceptions \
_pie_fixup_size=0
/* --------------------------------------------------------------------
* Perform BL1 setup
* --------------------------------------------------------------------
*/
bl bl1_setup
#if ENABLE_PAUTH
/* --------------------------------------------------------------------
* Program APIAKey_EL1 and enable pointer authentication.
* --------------------------------------------------------------------
*/
bl pauth_init_enable_el3
#endif /* ENABLE_PAUTH */
/* --------------------------------------------------------------------
* Initialize platform and jump to our c-entry point
* for this type of reset.
* --------------------------------------------------------------------
*/
bl bl1_main
#if ENABLE_PAUTH
/* --------------------------------------------------------------------
* Disable pointer authentication before jumping to next boot image.
* --------------------------------------------------------------------
*/
bl pauth_disable_el3
#endif /* ENABLE_PAUTH */
/* --------------------------------------------------
* Do the transition to next boot image.
* --------------------------------------------------
*/
#if ENABLE_RME
b bl1_run_bl2_in_root
#else
b el3_exit
#endif
endfunc bl1_entrypoint
/* -----------------------------------------------------
* void bl1_run_bl2_in_root();
* This function runs BL2 in root/EL3 when RME is enabled.
* -----------------------------------------------------
*/
func bl1_run_bl2_in_root
/* read bl2_ep_info */
adrp x20, bl2_ep_info
add x20, x20, :lo12:bl2_ep_info
ldr x20, [x20]
/* ---------------------------------------------
* MMU needs to be disabled because BL2 executes
* in EL3. It will initialize the address space
* according to its own requirements.
* ---------------------------------------------
*/
bl disable_mmu_icache_el3
tlbi alle3
ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
msr elr_el3, x0
msr spsr_el3, x1
ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
exception_return
endfunc bl1_run_bl2_in_root

View File

@@ -0,0 +1,289 @@
/*
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <context.h>
/* -----------------------------------------------------------------------------
* Very simple stackless exception handlers used by BL1.
* -----------------------------------------------------------------------------
*/
.globl bl1_exceptions
vector_base bl1_exceptions
/* -----------------------------------------------------
* Current EL with SP0 : 0x0 - 0x200
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSP0
mov x0, #SYNC_EXCEPTION_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionSP0
vector_entry IrqSP0
mov x0, #IRQ_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqSP0
vector_entry FiqSP0
mov x0, #FIQ_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqSP0
vector_entry SErrorSP0
mov x0, #SERROR_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorSP0
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x400
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSPx
mov x0, #SYNC_EXCEPTION_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionSPx
vector_entry IrqSPx
mov x0, #IRQ_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqSPx
vector_entry FiqSPx
mov x0, #FIQ_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqSPx
vector_entry SErrorSPx
mov x0, #SERROR_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorSPx
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA64
/* Enable the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
/* Expect only SMC exceptions */
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
cmp x30, #EC_AARCH64_SMC
b.ne unexpected_sync_exception
b smc_handler64
end_vector_entry SynchronousExceptionA64
vector_entry IrqA64
mov x0, #IRQ_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqA64
vector_entry FiqA64
mov x0, #FIQ_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqA64
vector_entry SErrorA64
mov x0, #SERROR_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorA64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA32
mov x0, #SYNC_EXCEPTION_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionA32
vector_entry IrqA32
mov x0, #IRQ_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqA32
vector_entry FiqA32
mov x0, #FIQ_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqA32
vector_entry SErrorA32
mov x0, #SERROR_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorA32
func smc_handler64
/* ----------------------------------------------
* Detect if this is a RUN_IMAGE or other SMC.
* ----------------------------------------------
*/
mov x30, #BL1_SMC_RUN_IMAGE
cmp x30, x0
b.ne smc_handler
/* ------------------------------------------------
* Make sure only Secure world reaches here.
* ------------------------------------------------
*/
mrs x30, scr_el3
tst x30, #SCR_NS_BIT
b.ne unexpected_sync_exception
/* ----------------------------------------------
* Handling RUN_IMAGE SMC. First switch back to
* SP_EL0 for the C runtime stack.
* ----------------------------------------------
*/
ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
msr spsel, #MODE_SP_EL0
mov sp, x30
/* ---------------------------------------------------------------------
* Pass EL3 control to next BL image.
* Here it expects X1 with the address of a entry_point_info_t
* structure describing the next BL image entrypoint.
* ---------------------------------------------------------------------
*/
mov x20, x1
mov x0, x20
bl bl1_print_next_bl_ep_info
ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
msr elr_el3, x0
msr spsr_el3, x1
ubfx x0, x1, #MODE_EL_SHIFT, #2
cmp x0, #MODE_EL3
b.ne unexpected_sync_exception
bl disable_mmu_icache_el3
tlbi alle3
dsb ish /* ERET implies ISB, so it is not needed here */
#if SPIN_ON_BL1_EXIT
bl print_debug_loop_message
debug_loop:
b debug_loop
#endif
mov x0, x20
bl bl1_plat_prepare_exit
ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
exception_return
endfunc smc_handler64
unexpected_sync_exception:
mov x0, #SYNC_EXCEPTION_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
/* -----------------------------------------------------
* Save Secure/Normal world context and jump to
* BL1 SMC handler.
* -----------------------------------------------------
*/
smc_handler:
/* -----------------------------------------------------
* Save x0-x29 and ARMv8.3-PAuth (if enabled) registers.
* If Secure Cycle Counter is not disabled in MDCR_EL3
* when ARMv8.5-PMU is implemented, save PMCR_EL0 and
* disable Cycle Counter.
* TODO: Revisit to store only SMCCC specified registers.
* -----------------------------------------------------
*/
bl prepare_el3_entry
#if ENABLE_PAUTH
/* -----------------------------------------------------
* Load and program stored APIAKey firmware key.
* Re-enable pointer authentication in EL3, as it was
* disabled before jumping to the next boot image.
* -----------------------------------------------------
*/
bl pauth_load_bl1_apiakey_enable
#endif
/* -----------------------------------------------------
* Populate the parameters for the SMC handler. We
* already have x0-x4 in place. x5 will point to a
* cookie (not used now). x6 will point to the context
* structure (SP_EL3) and x7 will contain flags we need
* to pass to the handler.
* -----------------------------------------------------
*/
mov x5, xzr
mov x6, sp
/* -----------------------------------------------------
* Restore the saved C runtime stack value which will
* become the new SP_EL0 i.e. EL3 runtime stack. It was
* saved in the 'cpu_context' structure prior to the last
* ERET from EL3.
* -----------------------------------------------------
*/
ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
/* ---------------------------------------------
* Switch back to SP_EL0 for the C runtime stack.
* ---------------------------------------------
*/
msr spsel, #MODE_SP_EL0
mov sp, x12
/* -----------------------------------------------------
* Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there
* is a world switch during SMC handling.
* -----------------------------------------------------
*/
mrs x16, spsr_el3
mrs x17, elr_el3
mrs x18, scr_el3
stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
bfi x7, x18, #0, #1
/* -----------------------------------------------------
* Go to BL1 SMC handler.
* -----------------------------------------------------
*/
bl bl1_smc_handler
/* -----------------------------------------------------
* Do the transition to next BL image.
* -----------------------------------------------------
*/
b el3_exit

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* The .data section gets copied from ROM to RAM at runtime.
* Its LMA should be 16-byte aligned to allow efficient copying of 16-bytes
* aligned regions in it.
* Its VMA must be page-aligned as it marks the first read/write page.
*/
#define DATA_ALIGN 16
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl1_entrypoint)
MEMORY {
ROM (rx): ORIGIN = BL1_RO_BASE, LENGTH = BL1_RO_LIMIT - BL1_RO_BASE
RAM (rwx): ORIGIN = BL1_RW_BASE, LENGTH = BL1_RW_LIMIT - BL1_RW_BASE
}
SECTIONS
{
. = BL1_RO_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL1_RO_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
*bl1_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >ROM
/* .ARM.extab and .ARM.exidx are only added because Clang need them */
.ARM.extab . : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >ROM
.ARM.exidx . : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >ROM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
/*
* No need to pad out the .rodata section to a page boundary. Next is
* the .data section, which can mapped in ROM with the same memory
* attributes as the .rodata section.
*
* Pad out to 16 bytes though as .data section needs to be 16 byte
* aligned and lld does not align the LMA to the aligment specified
* on the .data section.
*/
__RODATA_END__ = .;
. = ALIGN(16);
} >ROM
#else
ro . : {
__RO_START__ = .;
*bl1_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
*(.vectors)
__RO_END__ = .;
/*
* Pad out to 16 bytes as .data section needs to be 16 byte aligned and
* lld does not align the LMA to the aligment specified on the .data
* section.
*/
. = ALIGN(16);
} >ROM
#endif
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
. = BL1_RW_BASE;
ASSERT(BL1_RW_BASE == ALIGN(PAGE_SIZE),
"BL1_RW_BASE address is not aligned on a page boundary.")
DATA_SECTION >RAM AT>ROM
__DATA_RAM_START__ = __DATA_START__;
__DATA_RAM_END__ = __DATA_END__;
STACK_SECTION >RAM
BSS_SECTION >RAM
XLAT_TABLE_SECTION >RAM
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
__BL1_RAM_START__ = ADDR(.data);
__BL1_RAM_END__ = .;
__DATA_ROM_START__ = LOADADDR(.data);
__DATA_SIZE__ = SIZEOF(.data);
/*
* The .data section is the last PROGBITS section so its end marks the end
* of BL1's actual content in Trusted ROM.
*/
__BL1_ROM_END__ = __DATA_ROM_START__ + __DATA_SIZE__;
ASSERT(__BL1_ROM_END__ <= BL1_RO_LIMIT,
"BL1's ROM content has exceeded its limit.")
__BSS_SIZE__ = SIZEOF(.bss);
#if USE_COHERENT_MEM
__COHERENT_RAM_UNALIGNED_SIZE__ =
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif
ASSERT(. <= BL1_RW_LIMIT, "BL1's RW section has exceeded its limit.")
}

View File

@@ -0,0 +1,32 @@
#
# Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
BL1_SOURCES += bl1/${ARCH}/bl1_arch_setup.c \
bl1/${ARCH}/bl1_context_mgmt.c \
bl1/${ARCH}/bl1_entrypoint.S \
bl1/${ARCH}/bl1_exceptions.S \
bl1/bl1_main.c \
lib/cpus/${ARCH}/cpu_helpers.S \
lib/cpus/errata_report.c \
lib/el3_runtime/${ARCH}/context_mgmt.c \
plat/common/plat_bl1_common.c \
plat/common/${ARCH}/platform_up_stack.S \
${MBEDTLS_SOURCES}
ifeq (${DISABLE_MTPMU},1)
BL1_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
endif
ifeq (${ARCH},aarch64)
BL1_SOURCES += lib/cpus/aarch64/dsu_helpers.S \
lib/el3_runtime/aarch64/context.S
endif
ifeq (${TRUSTED_BOARD_BOOT},1)
BL1_SOURCES += bl1/bl1_fwu.c
endif
BL1_LINKERFILE := bl1/bl1.ld.S

View File

@@ -0,0 +1,745 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <string.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <drivers/auth/auth_mod.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <smccc_helpers.h>
#include "bl1_private.h"
/*
* Function declarations.
*/
static int bl1_fwu_image_copy(unsigned int image_id,
uintptr_t image_src,
unsigned int block_size,
unsigned int image_size,
unsigned int flags);
static int bl1_fwu_image_auth(unsigned int image_id,
uintptr_t image_src,
unsigned int image_size,
unsigned int flags);
static int bl1_fwu_image_execute(unsigned int image_id,
void **handle,
unsigned int flags);
static register_t bl1_fwu_image_resume(register_t image_param,
void **handle,
unsigned int flags);
static int bl1_fwu_sec_image_done(void **handle,
unsigned int flags);
static int bl1_fwu_image_reset(unsigned int image_id,
unsigned int flags);
__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved);
/*
* This keeps track of last executed secure image id.
*/
static unsigned int sec_exec_image_id = INVALID_IMAGE_ID;
/*******************************************************************************
* Top level handler for servicing FWU SMCs.
******************************************************************************/
u_register_t bl1_fwu_smc_handler(unsigned int smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
unsigned int flags)
{
switch (smc_fid) {
case FWU_SMC_IMAGE_COPY:
SMC_RET1(handle, bl1_fwu_image_copy((uint32_t)x1, x2,
(uint32_t)x3, (uint32_t)x4, flags));
case FWU_SMC_IMAGE_AUTH:
SMC_RET1(handle, bl1_fwu_image_auth((uint32_t)x1, x2,
(uint32_t)x3, flags));
case FWU_SMC_IMAGE_EXECUTE:
SMC_RET1(handle, bl1_fwu_image_execute((uint32_t)x1, &handle,
flags));
case FWU_SMC_IMAGE_RESUME:
SMC_RET1(handle, bl1_fwu_image_resume((register_t)x1, &handle,
flags));
case FWU_SMC_SEC_IMAGE_DONE:
SMC_RET1(handle, bl1_fwu_sec_image_done(&handle, flags));
case FWU_SMC_IMAGE_RESET:
SMC_RET1(handle, bl1_fwu_image_reset((uint32_t)x1, flags));
case FWU_SMC_UPDATE_DONE:
bl1_fwu_done((void *)x1, NULL);
default:
assert(false); /* Unreachable */
break;
}
SMC_RET1(handle, SMC_UNK);
}
/*******************************************************************************
* Utility functions to keep track of the images that are loaded at any time.
******************************************************************************/
#ifdef PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
#define FWU_MAX_SIMULTANEOUS_IMAGES PLAT_FWU_MAX_SIMULTANEOUS_IMAGES
#else
#define FWU_MAX_SIMULTANEOUS_IMAGES 10
#endif
static unsigned int bl1_fwu_loaded_ids[FWU_MAX_SIMULTANEOUS_IMAGES] = {
[0 ... FWU_MAX_SIMULTANEOUS_IMAGES-1] = INVALID_IMAGE_ID
};
/*
* Adds an image_id to the bl1_fwu_loaded_ids array.
* Returns 0 on success, 1 on error.
*/
static int bl1_fwu_add_loaded_id(unsigned int image_id)
{
int i;
/* Check if the ID is already in the list */
for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
if (bl1_fwu_loaded_ids[i] == image_id)
return 0;
}
/* Find an empty slot */
for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
if (bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) {
bl1_fwu_loaded_ids[i] = image_id;
return 0;
}
}
return 1;
}
/*
* Removes an image_id from the bl1_fwu_loaded_ids array.
* Returns 0 on success, 1 on error.
*/
static int bl1_fwu_remove_loaded_id(unsigned int image_id)
{
int i;
/* Find the ID */
for (i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
if (bl1_fwu_loaded_ids[i] == image_id) {
bl1_fwu_loaded_ids[i] = INVALID_IMAGE_ID;
return 0;
}
}
return 1;
}
/*******************************************************************************
* This function checks if the specified image overlaps another image already
* loaded. It returns 0 if there is no overlap, a negative error code otherwise.
******************************************************************************/
static int bl1_fwu_image_check_overlaps(unsigned int image_id)
{
const image_desc_t *desc, *checked_desc;
const image_info_t *info, *checked_info;
uintptr_t image_base, image_end;
uintptr_t checked_image_base, checked_image_end;
checked_desc = bl1_plat_get_image_desc(image_id);
checked_info = &checked_desc->image_info;
/* Image being checked mustn't be empty. */
assert(checked_info->image_size != 0);
checked_image_base = checked_info->image_base;
checked_image_end = checked_image_base + checked_info->image_size - 1;
/* No need to check for overflows, it's done in bl1_fwu_image_copy(). */
for (int i = 0; i < FWU_MAX_SIMULTANEOUS_IMAGES; i++) {
/* Skip INVALID_IMAGE_IDs and don't check image against itself */
if ((bl1_fwu_loaded_ids[i] == INVALID_IMAGE_ID) ||
(bl1_fwu_loaded_ids[i] == image_id))
continue;
desc = bl1_plat_get_image_desc(bl1_fwu_loaded_ids[i]);
/* Only check images that are loaded or being loaded. */
assert ((desc != NULL) && (desc->state != IMAGE_STATE_RESET));
info = &desc->image_info;
/* There cannot be overlaps with an empty image. */
if (info->image_size == 0)
continue;
image_base = info->image_base;
image_end = image_base + info->image_size - 1;
/*
* Overflows cannot happen. It is checked in
* bl1_fwu_image_copy() when the image goes from RESET to
* COPYING or COPIED.
*/
assert (image_end > image_base);
/* Check if there are overlaps. */
if (!((image_end < checked_image_base) ||
(checked_image_end < image_base))) {
VERBOSE("Image with ID %d overlaps existing image with ID %d",
checked_desc->image_id, desc->image_id);
return -EPERM;
}
}
return 0;
}
/*******************************************************************************
* This function is responsible for copying secure images in AP Secure RAM.
******************************************************************************/
static int bl1_fwu_image_copy(unsigned int image_id,
uintptr_t image_src,
unsigned int block_size,
unsigned int image_size,
unsigned int flags)
{
uintptr_t dest_addr;
unsigned int remaining;
image_desc_t *desc;
/* Get the image descriptor. */
desc = bl1_plat_get_image_desc(image_id);
if (desc == NULL) {
WARN("BL1-FWU: Invalid image ID %u\n", image_id);
return -EPERM;
}
/*
* The request must originate from a non-secure caller and target a
* secure image. Any other scenario is invalid.
*/
if (GET_SECURITY_STATE(flags) == SECURE) {
WARN("BL1-FWU: Copy not allowed from secure world.\n");
return -EPERM;
}
if (GET_SECURITY_STATE(desc->ep_info.h.attr) == NON_SECURE) {
WARN("BL1-FWU: Copy not allowed for non-secure images.\n");
return -EPERM;
}
/* Check whether the FWU state machine is in the correct state. */
if ((desc->state != IMAGE_STATE_RESET) &&
(desc->state != IMAGE_STATE_COPYING)) {
WARN("BL1-FWU: Copy not allowed at this point of the FWU"
" process.\n");
return -EPERM;
}
if ((image_src == 0U) || (block_size == 0U) ||
check_uptr_overflow(image_src, block_size - 1)) {
WARN("BL1-FWU: Copy not allowed due to invalid image source"
" or block size\n");
return -ENOMEM;
}
if (desc->state == IMAGE_STATE_COPYING) {
/*
* There must have been at least 1 copy operation for this image
* previously.
*/
assert(desc->copied_size != 0U);
/*
* The image size must have been recorded in the 1st copy
* operation.
*/
image_size = desc->image_info.image_size;
assert(image_size != 0);
assert(desc->copied_size < image_size);
INFO("BL1-FWU: Continuing image copy in blocks\n");
} else { /* desc->state == IMAGE_STATE_RESET */
INFO("BL1-FWU: Initial call to copy an image\n");
/*
* image_size is relevant only for the 1st copy request, it is
* then ignored for subsequent calls for this image.
*/
if (image_size == 0) {
WARN("BL1-FWU: Copy not allowed due to invalid image"
" size\n");
return -ENOMEM;
}
/* Check that the image size to load is within limit */
if (image_size > desc->image_info.image_max_size) {
WARN("BL1-FWU: Image size out of bounds\n");
return -ENOMEM;
}
/* Save the given image size. */
desc->image_info.image_size = image_size;
/* Make sure the image doesn't overlap other images. */
if (bl1_fwu_image_check_overlaps(image_id) != 0) {
desc->image_info.image_size = 0;
WARN("BL1-FWU: This image overlaps another one\n");
return -EPERM;
}
/*
* copied_size must be explicitly initialized here because the
* FWU code doesn't necessarily do it when it resets the state
* machine.
*/
desc->copied_size = 0;
}
/*
* If the given block size is more than the total image size
* then clip the former to the latter.
*/
remaining = image_size - desc->copied_size;
if (block_size > remaining) {
WARN("BL1-FWU: Block size is too big, clipping it.\n");
block_size = remaining;
}
/* Make sure the source image is mapped in memory. */
if (bl1_plat_mem_check(image_src, block_size, flags) != 0) {
WARN("BL1-FWU: Source image is not mapped.\n");
return -ENOMEM;
}
if (bl1_fwu_add_loaded_id(image_id) != 0) {
WARN("BL1-FWU: Too many images loaded at the same time.\n");
return -ENOMEM;
}
/* Allow the platform to handle pre-image load before copying */
if (desc->state == IMAGE_STATE_RESET) {
if (bl1_plat_handle_pre_image_load(image_id) != 0) {
ERROR("BL1-FWU: Failure in pre-image load of image id %d\n",
image_id);
return -EPERM;
}
}
/* Everything looks sane. Go ahead and copy the block of data. */
dest_addr = desc->image_info.image_base + desc->copied_size;
(void)memcpy((void *) dest_addr, (const void *) image_src, block_size);
flush_dcache_range(dest_addr, block_size);
desc->copied_size += block_size;
desc->state = (block_size == remaining) ?
IMAGE_STATE_COPIED : IMAGE_STATE_COPYING;
INFO("BL1-FWU: Copy operation successful.\n");
return 0;
}
/*******************************************************************************
* This function is responsible for authenticating Normal/Secure images.
******************************************************************************/
static int bl1_fwu_image_auth(unsigned int image_id,
uintptr_t image_src,
unsigned int image_size,
unsigned int flags)
{
int result;
uintptr_t base_addr;
unsigned int total_size;
image_desc_t *desc;
/* Get the image descriptor. */
desc = bl1_plat_get_image_desc(image_id);
if (desc == NULL)
return -EPERM;
if (GET_SECURITY_STATE(flags) == SECURE) {
if (desc->state != IMAGE_STATE_RESET) {
WARN("BL1-FWU: Authentication from secure world "
"while in invalid state\n");
return -EPERM;
}
} else {
if (GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE) {
if (desc->state != IMAGE_STATE_COPIED) {
WARN("BL1-FWU: Authentication of secure image "
"from non-secure world while not in copied state\n");
return -EPERM;
}
} else {
if (desc->state != IMAGE_STATE_RESET) {
WARN("BL1-FWU: Authentication of non-secure image "
"from non-secure world while in invalid state\n");
return -EPERM;
}
}
}
if (desc->state == IMAGE_STATE_COPIED) {
/*
* Image is in COPIED state.
* Use the stored address and size.
*/
base_addr = desc->image_info.image_base;
total_size = desc->image_info.image_size;
} else {
if ((image_src == 0U) || (image_size == 0U) ||
check_uptr_overflow(image_src, image_size - 1)) {
WARN("BL1-FWU: Auth not allowed due to invalid"
" image source/size\n");
return -ENOMEM;
}
/*
* Image is in RESET state.
* Check the parameters and authenticate the source image in place.
*/
if (bl1_plat_mem_check(image_src, image_size, \
desc->ep_info.h.attr) != 0) {
WARN("BL1-FWU: Authentication arguments source/size not mapped\n");
return -ENOMEM;
}
if (bl1_fwu_add_loaded_id(image_id) != 0) {
WARN("BL1-FWU: Too many images loaded at the same time.\n");
return -ENOMEM;
}
base_addr = image_src;
total_size = image_size;
/* Update the image size in the descriptor. */
desc->image_info.image_size = total_size;
}
/*
* Authenticate the image.
*/
INFO("BL1-FWU: Authenticating image_id:%d\n", image_id);
result = auth_mod_verify_img(image_id, (void *)base_addr, total_size);
if (result != 0) {
WARN("BL1-FWU: Authentication Failed err=%d\n", result);
/*
* Authentication has failed.
* Clear the memory if the image was copied.
* This is to prevent an attack where this contains
* some malicious code that can somehow be executed later.
*/
if (desc->state == IMAGE_STATE_COPIED) {
/* Clear the memory.*/
zero_normalmem((void *)base_addr, total_size);
flush_dcache_range(base_addr, total_size);
/* Indicate that image can be copied again*/
desc->state = IMAGE_STATE_RESET;
}
/*
* Even if this fails it's ok because the ID isn't in the array.
* The image cannot be in RESET state here, it is checked at the
* beginning of the function.
*/
(void)bl1_fwu_remove_loaded_id(image_id);
return -EAUTH;
}
/* Indicate that image is in authenticated state. */
desc->state = IMAGE_STATE_AUTHENTICATED;
/* Allow the platform to handle post-image load */
result = bl1_plat_handle_post_image_load(image_id);
if (result != 0) {
ERROR("BL1-FWU: Failure %d in post-image load of image id %d\n",
result, image_id);
/*
* Panic here as the platform handling of post-image load is
* not correct.
*/
plat_error_handler(result);
}
/*
* Flush image_info to memory so that other
* secure world images can see changes.
*/
flush_dcache_range((uintptr_t)&desc->image_info,
sizeof(image_info_t));
INFO("BL1-FWU: Authentication was successful\n");
return 0;
}
/*******************************************************************************
* This function is responsible for executing Secure images.
******************************************************************************/
static int bl1_fwu_image_execute(unsigned int image_id,
void **handle,
unsigned int flags)
{
/* Get the image descriptor. */
image_desc_t *desc = bl1_plat_get_image_desc(image_id);
/*
* Execution is NOT allowed if:
* image_id is invalid OR
* Caller is from Secure world OR
* Image is Non-Secure OR
* Image is Non-Executable OR
* Image is NOT in AUTHENTICATED state.
*/
if ((desc == NULL) ||
(GET_SECURITY_STATE(flags) == SECURE) ||
(GET_SECURITY_STATE(desc->ep_info.h.attr) == NON_SECURE) ||
(EP_GET_EXE(desc->ep_info.h.attr) == NON_EXECUTABLE) ||
(desc->state != IMAGE_STATE_AUTHENTICATED)) {
WARN("BL1-FWU: Execution not allowed due to invalid state/args\n");
return -EPERM;
}
INFO("BL1-FWU: Executing Secure image\n");
#ifdef __aarch64__
/* Save NS-EL1 system registers. */
cm_el1_sysregs_context_save(NON_SECURE);
#endif
/* Prepare the image for execution. */
bl1_prepare_next_image(image_id);
/* Update the secure image id. */
sec_exec_image_id = image_id;
#ifdef __aarch64__
*handle = cm_get_context(SECURE);
#else
*handle = smc_get_ctx(SECURE);
#endif
return 0;
}
/*******************************************************************************
* This function is responsible for resuming execution in the other security
* world
******************************************************************************/
static register_t bl1_fwu_image_resume(register_t image_param,
void **handle,
unsigned int flags)
{
image_desc_t *desc;
unsigned int resume_sec_state;
unsigned int caller_sec_state = GET_SECURITY_STATE(flags);
/* Get the image descriptor for last executed secure image id. */
desc = bl1_plat_get_image_desc(sec_exec_image_id);
if (caller_sec_state == NON_SECURE) {
if (desc == NULL) {
WARN("BL1-FWU: Resume not allowed due to no available"
"secure image\n");
return -EPERM;
}
} else {
/* desc must be valid for secure world callers */
assert(desc != NULL);
}
assert(GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE);
assert(EP_GET_EXE(desc->ep_info.h.attr) == EXECUTABLE);
if (caller_sec_state == SECURE) {
assert(desc->state == IMAGE_STATE_EXECUTED);
/* Update the flags. */
desc->state = IMAGE_STATE_INTERRUPTED;
resume_sec_state = NON_SECURE;
} else {
assert(desc->state == IMAGE_STATE_INTERRUPTED);
/* Update the flags. */
desc->state = IMAGE_STATE_EXECUTED;
resume_sec_state = SECURE;
}
INFO("BL1-FWU: Resuming %s world context\n",
(resume_sec_state == SECURE) ? "secure" : "normal");
#ifdef __aarch64__
/* Save the EL1 system registers of calling world. */
cm_el1_sysregs_context_save(caller_sec_state);
/* Restore the EL1 system registers of resuming world. */
cm_el1_sysregs_context_restore(resume_sec_state);
/* Update the next context. */
cm_set_next_eret_context(resume_sec_state);
*handle = cm_get_context(resume_sec_state);
#else
/* Update the next context. */
cm_set_next_context(cm_get_context(resume_sec_state));
/* Prepare the smc context for the next BL image. */
smc_set_next_ctx(resume_sec_state);
*handle = smc_get_ctx(resume_sec_state);
#endif
return image_param;
}
/*******************************************************************************
* This function is responsible for resuming normal world context.
******************************************************************************/
static int bl1_fwu_sec_image_done(void **handle, unsigned int flags)
{
image_desc_t *desc;
/* Make sure caller is from the secure world */
if (GET_SECURITY_STATE(flags) == NON_SECURE) {
WARN("BL1-FWU: Image done not allowed from normal world\n");
return -EPERM;
}
/* Get the image descriptor for last executed secure image id */
desc = bl1_plat_get_image_desc(sec_exec_image_id);
/* desc must correspond to a valid secure executing image */
assert(desc != NULL);
assert(GET_SECURITY_STATE(desc->ep_info.h.attr) == SECURE);
assert(EP_GET_EXE(desc->ep_info.h.attr) == EXECUTABLE);
assert(desc->state == IMAGE_STATE_EXECUTED);
#if ENABLE_ASSERTIONS
int rc = bl1_fwu_remove_loaded_id(sec_exec_image_id);
assert(rc == 0);
#else
bl1_fwu_remove_loaded_id(sec_exec_image_id);
#endif
/* Update the flags. */
desc->state = IMAGE_STATE_RESET;
sec_exec_image_id = INVALID_IMAGE_ID;
INFO("BL1-FWU: Resuming Normal world context\n");
#ifdef __aarch64__
/*
* Secure world is done so no need to save the context.
* Just restore the Non-Secure context.
*/
cm_el1_sysregs_context_restore(NON_SECURE);
/* Update the next context. */
cm_set_next_eret_context(NON_SECURE);
*handle = cm_get_context(NON_SECURE);
#else
/* Update the next context. */
cm_set_next_context(cm_get_context(NON_SECURE));
/* Prepare the smc context for the next BL image. */
smc_set_next_ctx(NON_SECURE);
*handle = smc_get_ctx(NON_SECURE);
#endif
return 0;
}
/*******************************************************************************
* This function provides the opportunity for users to perform any
* platform specific handling after the Firmware update is done.
******************************************************************************/
__dead2 static void bl1_fwu_done(void *client_cookie, void *reserved)
{
NOTICE("BL1-FWU: *******FWU Process Completed*******\n");
/*
* Call platform done function.
*/
bl1_plat_fwu_done(client_cookie, reserved);
assert(false);
}
/*******************************************************************************
* This function resets an image to IMAGE_STATE_RESET. It fails if the image is
* being executed.
******************************************************************************/
static int bl1_fwu_image_reset(unsigned int image_id, unsigned int flags)
{
image_desc_t *desc = bl1_plat_get_image_desc(image_id);
if ((desc == NULL) || (GET_SECURITY_STATE(flags) == SECURE)) {
WARN("BL1-FWU: Reset not allowed due to invalid args\n");
return -EPERM;
}
switch (desc->state) {
case IMAGE_STATE_RESET:
/* Nothing to do. */
break;
case IMAGE_STATE_INTERRUPTED:
case IMAGE_STATE_AUTHENTICATED:
case IMAGE_STATE_COPIED:
case IMAGE_STATE_COPYING:
if (bl1_fwu_remove_loaded_id(image_id) != 0) {
WARN("BL1-FWU: Image reset couldn't find the image ID\n");
return -EPERM;
}
if (desc->copied_size != 0U) {
/* Clear the memory if the image is copied */
assert(GET_SECURITY_STATE(desc->ep_info.h.attr)
== SECURE);
zero_normalmem((void *)desc->image_info.image_base,
desc->copied_size);
flush_dcache_range(desc->image_info.image_base,
desc->copied_size);
}
/* Reset status variables */
desc->copied_size = 0;
desc->image_info.image_size = 0;
desc->state = IMAGE_STATE_RESET;
/* Clear authentication state */
auth_img_flags[image_id] = 0;
break;
case IMAGE_STATE_EXECUTED:
default:
assert(false); /* Unreachable */
break;
}
return 0;
}

View File

@@ -0,0 +1,287 @@
/*
* Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <arch.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/console.h>
#include <lib/cpus/errata_report.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <smccc_helpers.h>
#include <tools_share/uuid.h>
#include "bl1_private.h"
static void bl1_load_bl2(void);
#if ENABLE_PAUTH
uint64_t bl1_apiakey[2];
#endif
/*******************************************************************************
* Helper utility to calculate the BL2 memory layout taking into consideration
* the BL1 RW data assuming that it is at the top of the memory layout.
******************************************************************************/
void bl1_calc_bl2_mem_layout(const meminfo_t *bl1_mem_layout,
meminfo_t *bl2_mem_layout)
{
assert(bl1_mem_layout != NULL);
assert(bl2_mem_layout != NULL);
/*
* Remove BL1 RW data from the scope of memory visible to BL2.
* This is assuming BL1 RW data is at the top of bl1_mem_layout.
*/
assert(BL1_RW_BASE > bl1_mem_layout->total_base);
bl2_mem_layout->total_base = bl1_mem_layout->total_base;
bl2_mem_layout->total_size = BL1_RW_BASE - bl1_mem_layout->total_base;
flush_dcache_range((uintptr_t)bl2_mem_layout, sizeof(meminfo_t));
}
/*******************************************************************************
* Setup function for BL1.
******************************************************************************/
void bl1_setup(void)
{
/* Perform early platform-specific setup */
bl1_early_platform_setup();
/* Perform late platform-specific setup */
bl1_plat_arch_setup();
#if CTX_INCLUDE_PAUTH_REGS
/*
* Assert that the ARMv8.3-PAuth registers are present or an access
* fault will be triggered when they are being saved or restored.
*/
assert(is_armv8_3_pauth_present());
#endif /* CTX_INCLUDE_PAUTH_REGS */
}
/*******************************************************************************
* Function to perform late architectural and platform specific initialization.
* It also queries the platform to load and run next BL image. Only called
* by the primary cpu after a cold boot.
******************************************************************************/
void bl1_main(void)
{
unsigned int image_id;
/* Announce our arrival */
NOTICE(FIRMWARE_WELCOME_STR);
NOTICE("BL1: %s\n", version_string);
NOTICE("BL1: %s\n", build_message);
INFO("BL1: RAM %p - %p\n", (void *)BL1_RAM_BASE, (void *)BL1_RAM_LIMIT);
print_errata_status();
#if ENABLE_ASSERTIONS
u_register_t val;
/*
* Ensure that MMU/Caches and coherency are turned on
*/
#ifdef __aarch64__
val = read_sctlr_el3();
#else
val = read_sctlr();
#endif
assert((val & SCTLR_M_BIT) != 0);
assert((val & SCTLR_C_BIT) != 0);
assert((val & SCTLR_I_BIT) != 0);
/*
* Check that Cache Writeback Granule (CWG) in CTR_EL0 matches the
* provided platform value
*/
val = (read_ctr_el0() >> CTR_CWG_SHIFT) & CTR_CWG_MASK;
/*
* If CWG is zero, then no CWG information is available but we can
* at least check the platform value is less than the architectural
* maximum.
*/
if (val != 0)
assert(CACHE_WRITEBACK_GRANULE == SIZE_FROM_LOG2_WORDS(val));
else
assert(CACHE_WRITEBACK_GRANULE <= MAX_CACHE_LINE_SIZE);
#endif /* ENABLE_ASSERTIONS */
/* Perform remaining generic architectural setup from EL3 */
bl1_arch_setup();
crypto_mod_init();
/* Initialize authentication module */
auth_mod_init();
/* Initialize the measured boot */
bl1_plat_mboot_init();
/* Perform platform setup in BL1. */
bl1_platform_setup();
#if ENABLE_PAUTH
/* Store APIAKey_EL1 key */
bl1_apiakey[0] = read_apiakeylo_el1();
bl1_apiakey[1] = read_apiakeyhi_el1();
#endif /* ENABLE_PAUTH */
/* Get the image id of next image to load and run. */
image_id = bl1_plat_get_next_image_id();
/*
* We currently interpret any image id other than
* BL2_IMAGE_ID as the start of firmware update.
*/
if (image_id == BL2_IMAGE_ID)
bl1_load_bl2();
else
NOTICE("BL1-FWU: *******FWU Process Started*******\n");
/* Teardown the measured boot driver */
bl1_plat_mboot_finish();
bl1_prepare_next_image(image_id);
console_flush();
}
/*******************************************************************************
* This function locates and loads the BL2 raw binary image in the trusted SRAM.
* Called by the primary cpu after a cold boot.
* TODO: Add support for alternative image load mechanism e.g using virtio/elf
* loader etc.
******************************************************************************/
static void bl1_load_bl2(void)
{
image_desc_t *desc;
image_info_t *info;
int err;
/* Get the image descriptor */
desc = bl1_plat_get_image_desc(BL2_IMAGE_ID);
assert(desc != NULL);
/* Get the image info */
info = &desc->image_info;
INFO("BL1: Loading BL2\n");
err = bl1_plat_handle_pre_image_load(BL2_IMAGE_ID);
if (err != 0) {
ERROR("Failure in pre image load handling of BL2 (%d)\n", err);
plat_error_handler(err);
}
err = load_auth_image(BL2_IMAGE_ID, info);
if (err != 0) {
ERROR("Failed to load BL2 firmware.\n");
plat_error_handler(err);
}
/* Allow platform to handle image information. */
err = bl1_plat_handle_post_image_load(BL2_IMAGE_ID);
if (err != 0) {
ERROR("Failure in post image load handling of BL2 (%d)\n", err);
plat_error_handler(err);
}
NOTICE("BL1: Booting BL2\n");
}
/*******************************************************************************
* Function called just before handing over to the next BL to inform the user
* about the boot progress. In debug mode, also print details about the BL
* image's execution context.
******************************************************************************/
void bl1_print_next_bl_ep_info(const entry_point_info_t *bl_ep_info)
{
#ifdef __aarch64__
NOTICE("BL1: Booting BL31\n");
#else
NOTICE("BL1: Booting BL32\n");
#endif /* __aarch64__ */
print_entry_point_info(bl_ep_info);
}
#if SPIN_ON_BL1_EXIT
void print_debug_loop_message(void)
{
NOTICE("BL1: Debug loop, spinning forever\n");
NOTICE("BL1: Please connect the debugger to continue\n");
}
#endif
/*******************************************************************************
* Top level handler for servicing BL1 SMCs.
******************************************************************************/
u_register_t bl1_smc_handler(unsigned int smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
unsigned int flags)
{
/* BL1 Service UUID */
DEFINE_SVC_UUID2(bl1_svc_uid,
U(0xd46739fd), 0xcb72, 0x9a4d, 0xb5, 0x75,
0x67, 0x15, 0xd6, 0xf4, 0xbb, 0x4a);
#if TRUSTED_BOARD_BOOT
/*
* Dispatch FWU calls to FWU SMC handler and return its return
* value
*/
if (is_fwu_fid(smc_fid)) {
return bl1_fwu_smc_handler(smc_fid, x1, x2, x3, x4, cookie,
handle, flags);
}
#endif
switch (smc_fid) {
case BL1_SMC_CALL_COUNT:
SMC_RET1(handle, BL1_NUM_SMC_CALLS);
case BL1_SMC_UID:
SMC_UUID_RET(handle, bl1_svc_uid);
case BL1_SMC_VERSION:
SMC_RET1(handle, BL1_SMC_MAJOR_VER | BL1_SMC_MINOR_VER);
default:
WARN("Unimplemented BL1 SMC Call: 0x%x\n", smc_fid);
SMC_RET1(handle, SMC_UNK);
}
}
/*******************************************************************************
* BL1 SMC wrapper. This function is only used in AArch32 mode to ensure ABI
* compliance when invoking bl1_smc_handler.
******************************************************************************/
u_register_t bl1_smc_wrapper(uint32_t smc_fid,
void *cookie,
void *handle,
unsigned int flags)
{
u_register_t x1, x2, x3, x4;
assert(handle != NULL);
get_smc_params_from_ctx(handle, x1, x2, x3, x4);
return bl1_smc_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BL1_PRIVATE_H
#define BL1_PRIVATE_H
#include <stdint.h>
#include <common/bl_common.h>
extern entry_point_info_t *bl2_ep_info;
/******************************************
* Function prototypes
*****************************************/
void bl1_arch_setup(void);
void bl1_arch_next_el_setup(void);
void bl1_prepare_next_image(unsigned int image_id);
void bl1_run_bl2_in_root(void);
u_register_t bl1_fwu_smc_handler(unsigned int smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
unsigned int flags);
#endif /* BL1_PRIVATE_H */

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <bl1/tbbr/tbbr_img_desc.h>
#include <common/bl_common.h>
image_desc_t bl1_tbbr_image_descs[] = {
{
.image_id = FWU_CERT_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
VERSION_1, image_info_t, 0),
.image_info.image_base = BL2_BASE,
.image_info.image_max_size = BL2_LIMIT - BL2_BASE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
VERSION_1, entry_point_info_t, SECURE),
},
#if NS_BL1U_BASE
{
.image_id = NS_BL1U_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_1, entry_point_info_t, NON_SECURE | EXECUTABLE),
.ep_info.pc = NS_BL1U_BASE,
},
#endif
#if SCP_BL2U_BASE
{
.image_id = SCP_BL2U_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY,
VERSION_1, image_info_t, 0),
.image_info.image_base = SCP_BL2U_BASE,
.image_info.image_max_size = SCP_BL2U_LIMIT - SCP_BL2U_BASE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY,
VERSION_1, entry_point_info_t, SECURE),
},
#endif
#if BL2U_BASE
{
.image_id = BL2U_IMAGE_ID,
SET_STATIC_PARAM_HEAD(image_info, PARAM_EP,
VERSION_1, image_info_t, 0),
.image_info.image_base = BL2U_BASE,
.image_info.image_max_size = BL2U_LIMIT - BL2U_BASE,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_1, entry_point_info_t, SECURE | EXECUTABLE),
.ep_info.pc = BL2U_BASE,
},
#endif
#if NS_BL2U_BASE
{
.image_id = NS_BL2U_IMAGE_ID,
SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP,
VERSION_1, entry_point_info_t, NON_SECURE),
},
#endif
BL2_IMAGE_DESC,
{
.image_id = INVALID_IMAGE_ID,
}
};

View File

@@ -0,0 +1,16 @@
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include "../bl2_private.h"
/*******************************************************************************
* Place holder function to perform any Secure SVC specific architectural
* setup. At the moment there is nothing to do.
******************************************************************************/
void bl2_arch_setup(void)
{
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <el3_common_macros.S>
.globl bl2_entrypoint
func bl2_entrypoint
/* Save arguments x0-x3 from previous Boot loader */
mov r9, r0
mov r10, r1
mov r11, r2
mov r12, r3
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=bl2_vector_table \
_pie_fixup_size=0
/*
* Restore parameters of boot rom
*/
mov r0, r9
mov r1, r10
mov r2, r11
mov r3, r12
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
bl bl2_el3_setup
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint

View File

@@ -0,0 +1,21 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_vector_table
vector_base bl2_vector_table
b bl2_entrypoint
b report_exception /* Undef */
b report_exception /* SVC call */
b report_exception /* Prefetch abort */
b report_exception /* Data abort */
b report_exception /* Reserved */
b report_exception /* IRQ */
b report_exception /* FIQ */

View File

@@ -0,0 +1,136 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_vector_table
.globl bl2_entrypoint
vector_base bl2_vector_table
b bl2_entrypoint
b report_exception /* Undef */
b report_exception /* SVC call */
b report_exception /* Prefetch abort */
b report_exception /* Data abort */
b report_exception /* Reserved */
b report_exception /* IRQ */
b report_exception /* FIQ */
func bl2_entrypoint
/*---------------------------------------------
* Save arguments x0 - x3 from BL1 for future
* use.
* ---------------------------------------------
*/
mov r9, r0
mov r10, r1
mov r11, r2
mov r12, r3
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
ldr r0, =bl2_vector_table
stcopr r0, VBAR
isb
/* --------------------------------------------------------
* Enable the instruction cache - disable speculative loads
* --------------------------------------------------------
*/
ldcopr r0, SCTLR
orr r0, r0, #SCTLR_I_BIT
bic r0, r0, #SCTLR_DSSBS_BIT
stcopr r0, SCTLR
isb
/* ---------------------------------------------
* Since BL2 executes after BL1, it is assumed
* here that BL1 has already has done the
* necessary register initializations.
* ---------------------------------------------
*/
/* ---------------------------------------------
* Invalidate the RW memory used by the BL2
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage.
* ---------------------------------------------
*/
ldr r0, =__RW_START__
ldr r1, =__RW_END__
sub r1, r1, r0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
ldr r0, =__BSS_START__
ldr r1, =__BSS_END__
sub r1, r1, r0
bl zeromem
#if USE_COHERENT_MEM
ldr r0, =__COHERENT_RAM_START__
ldr r1, =__COHERENT_RAM_END_UNALIGNED__
sub r1, r1, r0
bl zeromem
#endif
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
mov r0, r9
mov r1, r10
mov r2, r11
mov r3, r12
bl bl2_setup
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint

View File

@@ -0,0 +1,46 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_run_next_image
func bl2_run_next_image
mov r8,r0
/*
* MMU needs to be disabled because both BL2 and BL32 execute
* in PL1, and therefore share the same address space.
* BL32 will initialize the address space according to its
* own requirement.
*/
bl disable_mmu_icache_secure
stcopr r0, TLBIALL
dsb sy
isb
mov r0, r8
bl bl2_el3_plat_prepare_exit
/*
* Extract PC and SPSR based on struct `entry_point_info_t`
* and load it in LR and SPSR registers respectively.
*/
ldr lr, [r8, #ENTRY_POINT_INFO_PC_OFFSET]
ldr r1, [r8, #(ENTRY_POINT_INFO_PC_OFFSET + 4)]
msr spsr_xc, r1
/* Some BL32 stages expect lr_svc to provide the BL33 entry address */
cps #MODE32_svc
ldr lr, [r8, #ENTRY_POINT_INFO_LR_SVC_OFFSET]
cps #MODE32_mon
add r8, r8, #ENTRY_POINT_INFO_ARGS_OFFSET
ldm r8, {r0, r1, r2, r3}
exception_return
endfunc bl2_run_next_image

View File

@@ -0,0 +1,19 @@
/*
* Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include "../bl2_private.h"
/*******************************************************************************
* Place holder function to perform any S-EL1 specific architectural setup. At
* the moment there is nothing to do.
******************************************************************************/
void bl2_arch_setup(void)
{
/* Give access to FP/SIMD registers */
write_cpacr(CPACR_EL1_FPEN(CPACR_EL1_FP_TRAP_NONE));
}

View File

@@ -0,0 +1,72 @@
/*
* Copyright (c) 2017-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <el3_common_macros.S>
.globl bl2_entrypoint
#if BL2_IN_XIP_MEM
#define FIXUP_SIZE 0
#else
#define FIXUP_SIZE ((BL2_LIMIT) - (BL2_BASE))
#endif
func bl2_entrypoint
/* Save arguments x0-x3 from previous Boot loader */
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=bl2_el3_exceptions \
_pie_fixup_size=FIXUP_SIZE
/* ---------------------------------------------
* Restore parameters of boot rom
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
bl bl2_el3_setup
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1 and enable pointer authentication.
* ---------------------------------------------
*/
bl pauth_init_enable_el3
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint

View File

@@ -0,0 +1,131 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl1/bl1.h>
#include <common/bl_common.h>
#include <context.h>
/* -----------------------------------------------------------------------------
* Very simple stackless exception handlers used by BL2.
* -----------------------------------------------------------------------------
*/
.globl bl2_el3_exceptions
vector_base bl2_el3_exceptions
/* -----------------------------------------------------
* Current EL with SP0 : 0x0 - 0x200
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSP0
mov x0, #SYNC_EXCEPTION_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionSP0
vector_entry IrqSP0
mov x0, #IRQ_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqSP0
vector_entry FiqSP0
mov x0, #FIQ_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqSP0
vector_entry SErrorSP0
mov x0, #SERROR_SP_EL0
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorSP0
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x400
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionSPx
mov x0, #SYNC_EXCEPTION_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionSPx
vector_entry IrqSPx
mov x0, #IRQ_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqSPx
vector_entry FiqSPx
mov x0, #FIQ_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqSPx
vector_entry SErrorSPx
mov x0, #SERROR_SP_ELX
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorSPx
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA64
mov x0, #SYNC_EXCEPTION_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionA64
vector_entry IrqA64
mov x0, #IRQ_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqA64
vector_entry FiqA64
mov x0, #FIQ_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqA64
vector_entry SErrorA64
mov x0, #SERROR_AARCH64
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorA64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800
* -----------------------------------------------------
*/
vector_entry SynchronousExceptionA32
mov x0, #SYNC_EXCEPTION_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SynchronousExceptionA32
vector_entry IrqA32
mov x0, #IRQ_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry IrqA32
vector_entry FiqA32
mov x0, #FIQ_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry FiqA32
vector_entry SErrorA32
mov x0, #SERROR_AARCH32
bl plat_report_exception
no_ret plat_panic_handler
end_vector_entry SErrorA32

View File

@@ -0,0 +1,141 @@
/*
* Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_entrypoint
func bl2_entrypoint
/*---------------------------------------------
* Save arguments x0 - x3 from BL1 for future
* use.
* ---------------------------------------------
*/
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
adr x0, early_exceptions
msr vbar_el1, x0
isb
/* ---------------------------------------------
* Enable the SError interrupt now that the
* exception vectors have been setup.
* ---------------------------------------------
*/
msr daifclr, #DAIF_ABT_BIT
/* ---------------------------------------------
* Enable the instruction cache, stack pointer
* and data access alignment checks and disable
* speculative loads.
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
bic x0, x0, #SCTLR_DSSBS_BIT
msr sctlr_el1, x0
isb
/* ---------------------------------------------
* Invalidate the RW memory used by the BL2
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage.
* ---------------------------------------------
*/
adr x0, __RW_START__
adr x1, __RW_END__
sub x1, x1, x0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
adrp x0, __BSS_START__
add x0, x0, :lo12:__BSS_START__
adrp x1, __BSS_END__
add x1, x1, :lo12:__BSS_END__
sub x1, x1, x0
bl zeromem
#if USE_COHERENT_MEM
adrp x0, __COHERENT_RAM_START__
add x0, x0, :lo12:__COHERENT_RAM_START__
adrp x1, __COHERENT_RAM_END_UNALIGNED__
add x1, x1, :lo12:__COHERENT_RAM_END_UNALIGNED__
sub x1, x1, x0
bl zeromem
#endif
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
bl bl2_setup
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1
* and enable pointer authentication.
* ---------------------------------------------
*/
bl pauth_init_enable_el1
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint

View File

@@ -0,0 +1,67 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <el3_common_macros.S>
.globl bl2_entrypoint
func bl2_entrypoint
/* Save arguments x0-x3 from previous Boot loader */
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
el3_entrypoint_common \
_init_sctlr=0 \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=1 \
_exception_vectors=bl2_el3_exceptions \
_pie_fixup_size=0
/* ---------------------------------------------
* Restore parameters of boot rom
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
/* ---------------------------------------------
* Perform BL2 setup
* ---------------------------------------------
*/
bl bl2_setup
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1 and enable pointer authentication.
* ---------------------------------------------
*/
bl pauth_init_enable_el3
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2_entrypoint

View File

@@ -0,0 +1,45 @@
/*
* Copyright (c) 2021, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2_run_next_image
func bl2_run_next_image
mov x20,x0
/* ---------------------------------------------
* MMU needs to be disabled because both BL2 and BL31 execute
* in EL3, and therefore share the same address space.
* BL31 will initialize the address space according to its
* own requirement.
* ---------------------------------------------
*/
bl disable_mmu_icache_el3
tlbi alle3
bl bl2_el3_plat_prepare_exit
#if ENABLE_PAUTH
/* ---------------------------------------------
* Disable pointer authentication before jumping
* to next boot image.
* ---------------------------------------------
*/
bl pauth_disable_el3
#endif /* ENABLE_PAUTH */
ldp x0, x1, [x20, #ENTRY_POINT_INFO_PC_OFFSET]
msr elr_el3, x0
msr spsr_el3, x1
ldp x6, x7, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x30)]
ldp x4, x5, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x20)]
ldp x2, x3, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x10)]
ldp x0, x1, [x20, #(ENTRY_POINT_INFO_ARGS_OFFSET + 0x0)]
exception_return
endfunc bl2_run_next_image

View File

@@ -0,0 +1,125 @@
/*
* Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl2_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE
}
SECTIONS
{
. = BL2_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL2_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
#if ENABLE_RME
*bl2_rme_entrypoint.o(.text*)
#else /* ENABLE_RME */
*bl2_entrypoint.o(.text*)
#endif /* ENABLE_RME */
*(SORT_BY_ALIGNMENT(.text*))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
/* .ARM.extab and .ARM.exidx are only added because Clang need them */
.ARM.extab . : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >RAM
.ARM.exidx . : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
ro . : {
__RO_START__ = .;
*bl2_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
STACK_SECTION >RAM
BSS_SECTION >RAM
XLAT_TABLE_SECTION >RAM
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL2_END__ = .;
__BSS_SIZE__ = SIZEOF(.bss);
#if USE_COHERENT_MEM
__COHERENT_RAM_UNALIGNED_SIZE__ =
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif
ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.")
}

View File

@@ -0,0 +1,50 @@
#
# Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
BL2_SOURCES += bl2/bl2_image_load_v2.c \
bl2/bl2_main.c \
bl2/${ARCH}/bl2_arch_setup.c \
lib/locks/exclusive/${ARCH}/spinlock.S \
plat/common/${ARCH}/platform_up_stack.S \
${MBEDTLS_SOURCES}
ifeq (${ARCH},aarch64)
BL2_SOURCES += common/aarch64/early_exceptions.S
endif
ifeq (${ENABLE_RME},1)
# Using RME, run BL2 at EL3
include lib/gpt_rme/gpt_rme.mk
BL2_SOURCES += bl2/${ARCH}/bl2_rme_entrypoint.S \
bl2/${ARCH}/bl2_el3_exceptions.S \
bl2/${ARCH}/bl2_run_next_image.S \
${GPT_LIB_SRCS}
BL2_LINKERFILE := bl2/bl2.ld.S
else ifeq (${BL2_AT_EL3},0)
# Normal operation, no RME, no BL2 at EL3
BL2_SOURCES += bl2/${ARCH}/bl2_entrypoint.S
BL2_LINKERFILE := bl2/bl2.ld.S
else
# BL2 at EL3, no RME
BL2_SOURCES += bl2/${ARCH}/bl2_el3_entrypoint.S \
bl2/${ARCH}/bl2_el3_exceptions.S \
bl2/${ARCH}/bl2_run_next_image.S \
lib/cpus/${ARCH}/cpu_helpers.S \
lib/cpus/errata_report.c
ifeq (${DISABLE_MTPMU},1)
BL2_SOURCES += lib/extensions/mtpmu/${ARCH}/mtpmu.S
endif
ifeq (${ARCH},aarch64)
BL2_SOURCES += lib/cpus/aarch64/dsu_helpers.S
endif
BL2_LINKERFILE := bl2/bl2_el3.ld.S
endif

View File

@@ -0,0 +1,187 @@
/*
* Copyright (c) 2017-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl2_entrypoint)
MEMORY {
#if BL2_IN_XIP_MEM
ROM (rx): ORIGIN = BL2_RO_BASE, LENGTH = BL2_RO_LIMIT - BL2_RO_BASE
RAM (rwx): ORIGIN = BL2_RW_BASE, LENGTH = BL2_RW_LIMIT - BL2_RW_BASE
#else
RAM (rwx): ORIGIN = BL2_BASE, LENGTH = BL2_LIMIT - BL2_BASE
#endif
#if SEPARATE_BL2_NOLOAD_REGION
RAM_NOLOAD (rw!a): ORIGIN = BL2_NOLOAD_START, LENGTH = BL2_NOLOAD_LIMIT - BL2_NOLOAD_START
#else
#define RAM_NOLOAD RAM
#endif
}
#if !BL2_IN_XIP_MEM
#define ROM RAM
#endif
SECTIONS
{
#if BL2_IN_XIP_MEM
. = BL2_RO_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL2_RO_BASE address is not aligned on a page boundary.")
#else
. = BL2_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL2_BASE address is not aligned on a page boundary.")
#endif
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
__TEXT_RESIDENT_START__ = .;
*bl2_el3_entrypoint.o(.text*)
*(.text.asm.*)
__TEXT_RESIDENT_END__ = .;
*(SORT_BY_ALIGNMENT(.text*))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >ROM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >ROM
ASSERT(__TEXT_RESIDENT_END__ - __TEXT_RESIDENT_START__ <= PAGE_SIZE,
"Resident part of BL2 has exceeded its limit.")
#else
ro . : {
__RO_START__ = .;
__TEXT_RESIDENT_START__ = .;
*bl2_el3_entrypoint.o(.text*)
*(.text.asm.*)
__TEXT_RESIDENT_END__ = .;
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >ROM
#endif
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
#if BL2_IN_XIP_MEM
. = BL2_RW_BASE;
ASSERT(BL2_RW_BASE == ALIGN(PAGE_SIZE),
"BL2_RW_BASE address is not aligned on a page boundary.")
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM AT>ROM
__DATA_RAM_START__ = __DATA_START__;
__DATA_RAM_END__ = __DATA_END__;
RELA_SECTION >RAM
#if SEPARATE_BL2_NOLOAD_REGION
SAVED_ADDR = .;
. = BL2_NOLOAD_START;
__BL2_NOLOAD_START__ = .;
#endif
STACK_SECTION >RAM_NOLOAD
BSS_SECTION >RAM_NOLOAD
XLAT_TABLE_SECTION >RAM_NOLOAD
#if SEPARATE_BL2_NOLOAD_REGION
__BL2_NOLOAD_END__ = .;
. = SAVED_ADDR;
#endif
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL2_END__ = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
}
#if BL2_IN_XIP_MEM
__BL2_RAM_START__ = ADDR(.data);
__BL2_RAM_END__ = .;
__DATA_ROM_START__ = LOADADDR(.data);
__DATA_SIZE__ = SIZEOF(.data);
/*
* The .data section is the last PROGBITS section so its end marks the end
* of BL2's RO content in XIP memory..
*/
__BL2_ROM_END__ = __DATA_ROM_START__ + __DATA_SIZE__;
ASSERT(__BL2_ROM_END__ <= BL2_RO_LIMIT,
"BL2's RO content has exceeded its limit.")
#endif
__BSS_SIZE__ = SIZEOF(.bss);
#if USE_COHERENT_MEM
__COHERENT_RAM_UNALIGNED_SIZE__ =
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif
#if BL2_IN_XIP_MEM
ASSERT(. <= BL2_RW_LIMIT, "BL2's RW content has exceeded its limit.")
#else
ASSERT(. <= BL2_LIMIT, "BL2 image has exceeded its limit.")
#endif
}

View File

@@ -0,0 +1,122 @@
/*
* Copyright (c) 2016-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <arch.h>
#include <arch_helpers.h>
#include "bl2_private.h"
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/desc_image_load.h>
#include <drivers/auth/auth_mod.h>
#include <plat/common/platform.h>
#include <platform_def.h>
__attribute__((weak)) int mtk_ar_update_bl_ar_ver(void)
{
return 0;
}
/*******************************************************************************
* This function loads SCP_BL2/BL3x images and returns the ep_info for
* the next executable image.
******************************************************************************/
struct entry_point_info *bl2_load_images(void)
{
bl_params_t *bl2_to_next_bl_params;
bl_load_info_t *bl2_load_info;
const bl_load_info_node_t *bl2_node_info;
int plat_setup_done = 0;
int err;
/*
* Get information about the images to load.
*/
bl2_load_info = plat_get_bl_image_load_info();
assert(bl2_load_info != NULL);
assert(bl2_load_info->head != NULL);
assert(bl2_load_info->h.type == PARAM_BL_LOAD_INFO);
assert(bl2_load_info->h.version >= VERSION_2);
bl2_node_info = bl2_load_info->head;
while (bl2_node_info != NULL) {
/*
* Perform platform setup before loading the image,
* if indicated in the image attributes AND if NOT
* already done before.
*/
if ((bl2_node_info->image_info->h.attr &
IMAGE_ATTRIB_PLAT_SETUP) != 0U) {
if (plat_setup_done != 0) {
WARN("BL2: Platform setup already done!!\n");
} else {
INFO("BL2: Doing platform setup\n");
bl2_platform_setup();
plat_setup_done = 1;
}
}
err = bl2_plat_handle_pre_image_load(bl2_node_info->image_id);
if (err != 0) {
ERROR("BL2: Failure in pre image load handling (%i)\n", err);
plat_error_handler(err);
}
if ((bl2_node_info->image_info->h.attr &
IMAGE_ATTRIB_SKIP_LOADING) == 0U) {
INFO("BL2: Loading image id %u\n", bl2_node_info->image_id);
err = load_auth_image(bl2_node_info->image_id,
bl2_node_info->image_info);
if (err != 0) {
ERROR("BL2: Failed to load image id %u (%i)\n",
bl2_node_info->image_id, err);
plat_error_handler(err);
}
} else {
INFO("BL2: Skip loading image id %u\n", bl2_node_info->image_id);
}
/* Allow platform to handle image information. */
err = bl2_plat_handle_post_image_load(bl2_node_info->image_id);
if (err != 0) {
ERROR("BL2: Failure in post image load handling (%i)\n", err);
plat_error_handler(err);
}
/* Go to next image */
bl2_node_info = bl2_node_info->next_load_info;
}
/*
* Get information to pass to the next image.
*/
bl2_to_next_bl_params = plat_get_next_bl_params();
assert(bl2_to_next_bl_params != NULL);
assert(bl2_to_next_bl_params->head != NULL);
assert(bl2_to_next_bl_params->h.type == PARAM_BL_PARAMS);
assert(bl2_to_next_bl_params->h.version >= VERSION_2);
assert(bl2_to_next_bl_params->head->ep_info != NULL);
/* Populate arg0 for the next BL image if not already provided */
if (bl2_to_next_bl_params->head->ep_info->args.arg0 == (u_register_t)0)
bl2_to_next_bl_params->head->ep_info->args.arg0 =
(u_register_t)bl2_to_next_bl_params;
/* Flush the parameters to be passed to next image */
plat_flush_next_bl_params();
/* Update boot loader anti-rollback version */
err = mtk_ar_update_bl_ar_ver();
if (err != 0) {
ERROR("BL2: Failure in updating anti-rollback version (%i)\n", err);
plat_error_handler(err);
}
return bl2_to_next_bl_params->head->ep_info;
}

View File

@@ -0,0 +1,149 @@
/*
* Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <arch_features.h>
#include <bl1/bl1.h>
#include <bl2/bl2.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/auth/crypto_mod.h>
#include <drivers/console.h>
#include <drivers/fwu/fwu.h>
#include <lib/extensions/pauth.h>
#include <plat/common/platform.h>
#include "bl2_private.h"
#ifdef __aarch64__
#define NEXT_IMAGE "BL31"
#else
#define NEXT_IMAGE "BL32"
#endif
#if BL2_AT_EL3
/*******************************************************************************
* Setup function for BL2 when BL2_AT_EL3=1
******************************************************************************/
void bl2_el3_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
u_register_t arg3)
{
/* Perform early platform-specific setup */
bl2_el3_early_platform_setup(arg0, arg1, arg2, arg3);
/* Perform late platform-specific setup */
bl2_el3_plat_arch_setup();
#if CTX_INCLUDE_PAUTH_REGS
/*
* Assert that the ARMv8.3-PAuth registers are present or an access
* fault will be triggered when they are being saved or restored.
*/
assert(is_armv8_3_pauth_present());
#endif /* CTX_INCLUDE_PAUTH_REGS */
}
#else /* BL2_AT_EL3 */
/*******************************************************************************
* Setup function for BL2 when BL2_AT_EL3=0
******************************************************************************/
void bl2_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
u_register_t arg3)
{
/* Perform early platform-specific setup */
bl2_early_platform_setup2(arg0, arg1, arg2, arg3);
/* Perform late platform-specific setup */
bl2_plat_arch_setup();
#if CTX_INCLUDE_PAUTH_REGS
/*
* Assert that the ARMv8.3-PAuth registers are present or an access
* fault will be triggered when they are being saved or restored.
*/
assert(is_armv8_3_pauth_present());
#endif /* CTX_INCLUDE_PAUTH_REGS */
}
#endif /* BL2_AT_EL3 */
/*******************************************************************************
* The only thing to do in BL2 is to load further images and pass control to
* next BL. The memory occupied by BL2 will be reclaimed by BL3x stages. BL2
* runs entirely in S-EL1.
******************************************************************************/
void bl2_main(void)
{
entry_point_info_t *next_bl_ep_info;
NOTICE("BL2: %s\n", version_string);
NOTICE("BL2: %s\n", build_message);
/* Perform remaining generic architectural setup in S-EL1 */
bl2_arch_setup();
#if PSA_FWU_SUPPORT
fwu_init();
#endif /* PSA_FWU_SUPPORT */
crypto_mod_init();
/* Initialize authentication module */
auth_mod_init();
/* Initialize the Measured Boot backend */
bl2_plat_mboot_init();
/* Initialize boot source */
bl2_plat_preload_setup();
/* Load the subsequent bootloader images. */
next_bl_ep_info = bl2_load_images();
/* Teardown the Measured Boot backend */
bl2_plat_mboot_finish();
#if !BL2_AT_EL3 && !ENABLE_RME
#ifndef __aarch64__
/*
* For AArch32 state BL1 and BL2 share the MMU setup.
* Given that BL2 does not map BL1 regions, MMU needs
* to be disabled in order to go back to BL1.
*/
disable_mmu_icache_secure();
#endif /* !__aarch64__ */
console_flush();
#if ENABLE_PAUTH
/*
* Disable pointer authentication before running next boot image
*/
pauth_disable_el1();
#endif /* ENABLE_PAUTH */
/*
* Run next BL image via an SMC to BL1. Information on how to pass
* control to the BL32 (if present) and BL33 software images will
* be passed to next BL image as an argument.
*/
smc(BL1_SMC_RUN_IMAGE, (unsigned long)next_bl_ep_info, 0, 0, 0, 0, 0, 0);
#else /* if BL2_AT_EL3 || ENABLE_RME */
NOTICE("BL2: Booting " NEXT_IMAGE "\n");
print_entry_point_info(next_bl_ep_info);
console_flush();
#if ENABLE_PAUTH
/*
* Disable pointer authentication before running next boot image
*/
pauth_disable_el3();
#endif /* ENABLE_PAUTH */
bl2_run_next_image(next_bl_ep_info);
#endif /* BL2_AT_EL3 && ENABLE_RME */
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright (c) 2013-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BL2_PRIVATE_H
#define BL2_PRIVATE_H
#include <common/bl_common.h>
/******************************************
* Forward declarations
*****************************************/
struct entry_point_info;
/******************************************
* Function prototypes
*****************************************/
void bl2_arch_setup(void);
struct entry_point_info *bl2_load_images(void);
void bl2_run_next_image(const struct entry_point_info *bl_ep_info);
#endif /* BL2_PRIVATE_H */

View File

@@ -0,0 +1,55 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2021 MediaTek Inc. All rights reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <platform_def.h>
.globl bl2pl_entrypoint
func bl2pl_entrypoint
/* Calculate the current load address */
adr r0, 1f
1: mov r1, #(1b - bl2pl_entrypoint)
sub r4, r0, r1
ldr r0, =__RO_START__
cmp r0, r4
beq 3f
/* Relocate ourself to original TEXT_BASE */
ldr r0, =__RO_START__
mov r1, r4
ldr r2, =__COPY_END__
2: ldr r3, [r1]
str r3, [r0]
add r0, r0, #4
add r1, r1, #4
cmp r0, r2
blt 2b
/* Clear BSS sction */
3: ldr r0, =__BSS_START__
ldr r1, =__BSS_END__
mov r2, #0
4: str r2, [r0]
add r0, r0, #4
cmp r0, r1
blt 4b
/* Setup stack */
ldr r0, =(BL2PL_LIMIT - 0x10)
mov sp, r0
# Jump to real main in original TEXT_BASE
mov r0, r4
ldr r1, =bl2pl_main
bx r1
endfunc bl2pl_entrypoint

View File

@@ -0,0 +1,54 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 2021 MediaTek Inc. All rights reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <platform_def.h>
.globl bl2pl_entrypoint
func bl2pl_entrypoint
/* Calculate the current load address */
adr x0, 1f
1: mov x1, #(1b - bl2pl_entrypoint)
sub x4, x0, x1
ldr x0, =__RO_START__
cmp x0, x4
beq 3f
/* Relocate ourself to original TEXT_BASE */
ldr x0, =__RO_START__
mov x1, x4
ldr x2, =__COPY_END__
2: ldr x3, [x1]
str x3, [x0]
add x0, x0, #8
add x1, x1, #8
cmp x0, x2
blt 2b
/* Clear BSS sction */
3: ldr x0, =__BSS_START__
ldr x1, =__BSS_END__
4: str xzr, [x0]
add x0, x0, #8
cmp x0, x1
blt 4b
/* Setup stack */
ldr x0, =(BL2PL_LIMIT - 0x10)
mov sp, x0
/* Jump to real main in original TEXT_BASE */
mov x0, x4
ldr x1, =bl2pl_main
br x1
endfunc bl2pl_entrypoint

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2021 MediaTek Inc. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl2pl_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = BL2PL_BASE, LENGTH = BL2PL_LIMIT - BL2PL_BASE
}
SECTIONS
{
. = BL2PL_BASE;
ro . : {
__RO_START__ = .;
*bl2pl_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
__RO_END__ = .;
} >RAM
DATA_SECTION >RAM
. = ALIGN(4);
.fill ALIGN(4) : {
LONG(0xffffffff)
} >RAM
__COPY_END__ = .;
__COPY_SIZE__ = __COPY_END__ - __RO_START__;
. = ALIGN(8);
BSS_SECTION >RAM
ASSERT(. <= BL2PL_LIMIT, "BL2PL image has exceeded its limit.")
}

View File

@@ -0,0 +1,13 @@
#
# Copyright (c) 2021 MediaTek Inc. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include lib/xz/xz.mk
BL2PL_SOURCES += bl2pl/bl2pl_main.c \
bl2pl/${ARCH}/bl2pl_entrypoint.S \
$(XZ_SOURCES)
BL2PL_LINKERFILE := bl2pl/bl2pl.ld.S

View File

@@ -0,0 +1,96 @@
// SPDX-License-Identifier: BSD-3-Clause
/*
* Copyright (C) 2021 MediaTek Inc. All rights reserved.
*
* Author: Weijie Gao <weijie.gao@mediatek.com>
*/
#include <common/bl_common.h>
#include <bl2pl/bl2pl.h>
#include <platform_def.h>
#include <string.h>
#include <tf_unxz.h>
#if defined(XZ_SIMPLE_PRINT_ERROR)
#define BL2PL_ERR xz_simple_puts
#else
#define BL2PL_ERR ERROR
#endif
extern uintptr_t __COPY_SIZE__;
static uint8_t xz_pool[0x6f50 + 0x4d8 + 0x50 + 1024];
#pragma weak bl2pl_platform_setup
void bl2pl_platform_setup(void)
{
}
int bl2pl_main(uintptr_t base_addr)
{
uintptr_t payload_addr, payload_new_addr, load_addr, outbuf;
uint32_t payload_size, bl2pl_size;
struct bl2pl_hdr *payload_hdr;
void (*pfunc)(void);
int ret;
bl2pl_platform_setup();
#if !defined(XZ_SIMPLE_PRINT_ERROR)
NOTICE("BL2PL: %s\n", version_string);
NOTICE("BL2PL: %s\n", build_message);
NOTICE("\n");
#endif
/* Locate the payload */
bl2pl_size = (uintptr_t)&__COPY_SIZE__;
payload_addr = base_addr + bl2pl_size;
/* Validate payload */
payload_hdr = (void *)payload_addr;
if (payload_hdr->magic != BL2PL_HDR_MAGIC) {
BL2PL_ERR("Invalid BL2 payload header\n");
goto fail;
}
if (payload_hdr->load_addr < L2_SRAM_BASE ||
payload_hdr->load_addr >= L2_SRAM_BASE + L2_SRAM_SIZE) {
BL2PL_ERR("Invalid BL2 payload load address\n");
goto fail;
}
if (payload_hdr->size > L2_SRAM_SIZE / 2) {
BL2PL_ERR("BL2 payload is too large\n");
goto fail;
}
/* Calculate new compressed payload address */
payload_new_addr = L2_SRAM_BASE + L2_SRAM_SIZE - payload_hdr->size;
payload_new_addr &= ~(0x10 - 1);
/* Move payload to end of SRAM */
memmove((void *)payload_new_addr,
(void *)payload_addr + sizeof(struct bl2pl_hdr),
payload_hdr->size);
/* Save payload information */
payload_size = payload_hdr->size;
load_addr = payload_hdr->load_addr;
/* Decompress payload */
outbuf = load_addr;
ret = unxz(&payload_new_addr, payload_size, &outbuf,
L2_SRAM_SIZE - payload_size, (uintptr_t)&xz_pool,
sizeof(xz_pool));
if (!ret) {
/* Jump to payload directly */
pfunc = (void (*)(void))load_addr;
(*pfunc)();
}
fail:
while (1);
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2u_vector_table
.globl bl2u_entrypoint
vector_base bl2u_vector_table
b bl2u_entrypoint
b report_exception /* Undef */
b report_exception /* SVC call */
b report_exception /* Prefetch abort */
b report_exception /* Data abort */
b report_exception /* Reserved */
b report_exception /* IRQ */
b report_exception /* FIQ */
func bl2u_entrypoint
/*---------------------------------------------
* Save from r1 the extents of the trusted ram
* available to BL2U for future use.
* r0 is not currently used.
* ---------------------------------------------
*/
mov r11, r1
mov r10, r2
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
ldr r0, =bl2u_vector_table
stcopr r0, VBAR
isb
/* --------------------------------------------------------
* Enable the instruction cache - disable speculative loads
* --------------------------------------------------------
*/
ldcopr r0, SCTLR
orr r0, r0, #SCTLR_I_BIT
bic r0, r0, #SCTLR_DSSBS_BIT
stcopr r0, SCTLR
isb
/* ---------------------------------------------
* Since BL2U executes after BL1, it is assumed
* here that BL1 has already has done the
* necessary register initializations.
* ---------------------------------------------
*/
/* ---------------------------------------------
* Invalidate the RW memory used by the BL2U
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage.
* ---------------------------------------------
*/
ldr r0, =__RW_START__
ldr r1, =__RW_END__
sub r1, r1, r0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
ldr r0, =__BSS_START__
ldr r1, =__BSS_END__
sub r1, r1, r0
bl zeromem
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform early platform setup & platform
* specific early arch. setup e.g. mmu setup
* ---------------------------------------------
*/
mov r0, r11
mov r1, r10
bl bl2u_early_platform_setup
bl bl2u_plat_arch_setup
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl bl2u_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2u_entrypoint

View File

@@ -0,0 +1,129 @@
/*
* Copyright (c) 2015-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
.globl bl2u_entrypoint
func bl2u_entrypoint
/*---------------------------------------------
* Store the extents of the tzram available to
* BL2U and other platform specific information
* for future use. x0 is currently not used.
* ---------------------------------------------
*/
mov x20, x1
mov x21, x2
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
adr x0, early_exceptions
msr vbar_el1, x0
isb
/* ---------------------------------------------
* Enable the SError interrupt now that the
* exception vectors have been setup.
* ---------------------------------------------
*/
msr daifclr, #DAIF_ABT_BIT
/* ---------------------------------------------
* Enable the instruction cache, stack pointer
* and data access alignment checks and disable
* speculative loads.
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
bic x0, x0, #SCTLR_DSSBS_BIT
msr sctlr_el1, x0
isb
/* ---------------------------------------------
* Invalidate the RW memory used by the BL2U
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage.
* ---------------------------------------------
*/
adr x0, __RW_START__
adr x1, __RW_END__
sub x1, x1, x0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
adrp x0, __BSS_START__
add x0, x0, :lo12:__BSS_START__
adrp x1, __BSS_END__
add x1, x1, :lo12:__BSS_END__
sub x1, x1, x0
bl zeromem
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform early platform setup & platform
* specific early arch. setup e.g. mmu setup
* ---------------------------------------------
*/
mov x0, x20
mov x1, x21
bl bl2u_early_platform_setup
bl bl2u_plat_arch_setup
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1
* and enable pointer authentication.
* ---------------------------------------------
*/
bl pauth_init_enable_el1
#endif
/* ---------------------------------------------
* Jump to bl2u_main function.
* ---------------------------------------------
*/
bl bl2u_main
/* ---------------------------------------------
* Should never reach this point.
* ---------------------------------------------
*/
no_ret plat_panic_handler
endfunc bl2u_entrypoint

View File

@@ -0,0 +1,118 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl2u_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = BL2U_BASE, LENGTH = BL2U_LIMIT - BL2U_BASE
}
SECTIONS
{
. = BL2U_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL2U_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
*bl2u_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
/* .ARM.extab and .ARM.exidx are only added because Clang need them */
.ARM.extab . : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >RAM
.ARM.exidx . : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
ro . : {
__RO_START__ = .;
*bl2u_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
STACK_SECTION >RAM
BSS_SECTION >RAM
XLAT_TABLE_SECTION >RAM
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL2U_END__ = .;
__BSS_SIZE__ = SIZEOF(.bss);
ASSERT(. <= BL2U_LIMIT, "BL2U image has exceeded its limit.")
}

View File

@@ -0,0 +1,15 @@
#
# Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
BL2U_SOURCES += bl2u/bl2u_main.c \
bl2u/${ARCH}/bl2u_entrypoint.S \
plat/common/${ARCH}/platform_up_stack.S
ifeq (${ARCH},aarch64)
BL2U_SOURCES += common/aarch64/early_exceptions.S
endif
BL2U_LINKERFILE := bl2u/bl2u.ld.S

View File

@@ -0,0 +1,65 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdint.h>
#include <platform_def.h>
#include <arch.h>
#include <arch_helpers.h>
#include <bl1/bl1.h>
#include <bl2u/bl2u.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/auth/auth_mod.h>
#include <drivers/console.h>
#include <plat/common/platform.h>
/*******************************************************************************
* This function is responsible to:
* Load SCP_BL2U if platform has defined SCP_BL2U_BASE
* Perform platform setup.
* Go back to EL3.
******************************************************************************/
void bl2u_main(void)
{
NOTICE("BL2U: %s\n", version_string);
NOTICE("BL2U: %s\n", build_message);
#if SCP_BL2U_BASE
int rc;
/* Load the subsequent bootloader images */
rc = bl2u_plat_handle_scp_bl2u();
if (rc != 0) {
ERROR("Failed to load SCP_BL2U (%i)\n", rc);
panic();
}
#endif
/* Perform platform setup in BL2U after loading SCP_BL2U */
bl2u_platform_setup();
console_flush();
#ifndef __aarch64__
/*
* For AArch32 state BL1 and BL2U share the MMU setup.
* Given that BL2U does not map BL1 regions, MMU needs
* to be disabled in order to go back to BL1.
*/
disable_mmu_icache_secure();
#endif /* !__aarch64__ */
/*
* Indicate that BL2U is done and resume back to
* normal world via an SMC to BL1.
* x1 could be passed to Normal world,
* so DO NOT pass any secret information.
*/
smc(FWU_SMC_SEC_IMAGE_DONE, 0, 0, 0, 0, 0, 0, 0);
wfi();
}

View File

@@ -0,0 +1,242 @@
/*
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <common/bl_common.h>
#include <el3_common_macros.S>
#include <lib/pmf/aarch64/pmf_asm_macros.S>
#include <lib/runtime_instr.h>
#include <lib/xlat_tables/xlat_mmu_helpers.h>
.globl bl31_entrypoint
.globl bl31_warm_entrypoint
/* -----------------------------------------------------
* bl31_entrypoint() is the cold boot entrypoint,
* executed only by the primary cpu.
* -----------------------------------------------------
*/
func bl31_entrypoint
/* ---------------------------------------------------------------
* Stash the previous bootloader arguments x0 - x3 for later use.
* ---------------------------------------------------------------
*/
mov x20, x0
mov x21, x1
mov x22, x2
mov x23, x3
#if !RESET_TO_BL31
/* ---------------------------------------------------------------------
* For !RESET_TO_BL31 systems, only the primary CPU ever reaches
* bl31_entrypoint() during the cold boot flow, so the cold/warm boot
* and primary/secondary CPU logic should not be executed in this case.
*
* Also, assume that the previous bootloader has already initialised the
* SCTLR_EL3, including the endianness, and has initialised the memory.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=0 \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=1 \
_exception_vectors=runtime_exceptions \
_pie_fixup_size=BL31_LIMIT - BL31_BASE
#else
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems which have a programmable reset address,
* bl31_entrypoint() is executed only on the cold boot path so we can
* skip the warm boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=runtime_exceptions \
_pie_fixup_size=BL31_LIMIT - BL31_BASE
#if !RESET_TO_BL31_WITH_PARAMS
/* ---------------------------------------------------------------------
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
* there's no argument to relay from a previous bootloader. Zero the
* arguments passed to the platform layer to reflect that.
* ---------------------------------------------------------------------
*/
mov x20, 0
mov x21, 0
mov x22, 0
mov x23, 0
#endif /* RESET_TO_BL31_WITH_PARAMS */
#endif /* RESET_TO_BL31 */
/* --------------------------------------------------------------------
* Perform BL31 setup
* --------------------------------------------------------------------
*/
mov x0, x20
mov x1, x21
mov x2, x22
mov x3, x23
bl bl31_setup
#if ENABLE_PAUTH
/* --------------------------------------------------------------------
* Program APIAKey_EL1 and enable pointer authentication
* --------------------------------------------------------------------
*/
bl pauth_init_enable_el3
#endif /* ENABLE_PAUTH */
/* --------------------------------------------------------------------
* Jump to main function
* --------------------------------------------------------------------
*/
bl bl31_main
/* --------------------------------------------------------------------
* Clean the .data & .bss sections to main memory. This ensures
* that any global data which was initialised by the primary CPU
* is visible to secondary CPUs before they enable their data
* caches and participate in coherency.
* --------------------------------------------------------------------
*/
adrp x0, __DATA_START__
add x0, x0, :lo12:__DATA_START__
adrp x1, __DATA_END__
add x1, x1, :lo12:__DATA_END__
sub x1, x1, x0
bl clean_dcache_range
adrp x0, __BSS_START__
add x0, x0, :lo12:__BSS_START__
adrp x1, __BSS_END__
add x1, x1, :lo12:__BSS_END__
sub x1, x1, x0
bl clean_dcache_range
b el3_exit
endfunc bl31_entrypoint
/* --------------------------------------------------------------------
* This CPU has been physically powered up. It is either resuming from
* suspend or has simply been turned on. In both cases, call the BL31
* warmboot entrypoint
* --------------------------------------------------------------------
*/
func bl31_warm_entrypoint
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* This timestamp update happens with cache off. The next
* timestamp collection will need to do cache maintenance prior
* to timestamp update.
*/
pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR
mrs x1, cntpct_el0
str x1, [x0]
#endif
/*
* On the warm boot path, most of the EL3 initialisations performed by
* 'el3_entrypoint_common' must be skipped:
*
* - Only when the platform bypasses the BL1/BL31 entrypoint by
* programming the reset address do we need to initialise SCTLR_EL3.
* In other cases, we assume this has been taken care by the
* entrypoint code.
*
* - No need to determine the type of boot, we know it is a warm boot.
*
* - Do not try to distinguish between primary and secondary CPUs, this
* notion only exists for a cold boot.
*
* - No need to initialise the memory or the C runtime environment,
* it has been done once and for all on the cold boot path.
*/
el3_entrypoint_common \
_init_sctlr=PROGRAMMABLE_RESET_ADDRESS \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=0 \
_exception_vectors=runtime_exceptions \
_pie_fixup_size=0
/*
* We're about to enable MMU and participate in PSCI state coordination.
*
* The PSCI implementation invokes platform routines that enable CPUs to
* participate in coherency. On a system where CPUs are not
* cache-coherent without appropriate platform specific programming,
* having caches enabled until such time might lead to coherency issues
* (resulting from stale data getting speculatively fetched, among
* others). Therefore we keep data caches disabled even after enabling
* the MMU for such platforms.
*
* On systems with hardware-assisted coherency, or on single cluster
* platforms, such platform specific programming is not required to
* enter coherency (as CPUs already are); and there's no reason to have
* caches disabled either.
*/
#if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY
mov x0, xzr
#else
mov x0, #DISABLE_DCACHE
#endif
bl bl31_plat_enable_mmu
#if ENABLE_RME
/*
* At warm boot GPT data structures have already been initialized in RAM
* but the sysregs for this CPU need to be initialized. Note that the GPT
* accesses are controlled attributes in GPCCR and do not depend on the
* SCR_EL3.C bit.
*/
bl gpt_enable
cbz x0, 1f
no_ret plat_panic_handler
1:
#endif
#if ENABLE_PAUTH
/* --------------------------------------------------------------------
* Program APIAKey_EL1 and enable pointer authentication
* --------------------------------------------------------------------
*/
bl pauth_init_enable_el3
#endif /* ENABLE_PAUTH */
bl psci_warmboot_entrypoint
#if ENABLE_RUNTIME_INSTRUMENTATION
pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_PSCI
mov x19, x0
/*
* Invalidate before updating timestamp to ensure previous timestamp
* updates on the same cache line with caches disabled are properly
* seen by the same core. Without the cache invalidate, the core might
* write into a stale cache line.
*/
mov x1, #PMF_TS_SIZE
mov x20, x30
bl inv_dcache_range
mov x30, x20
mrs x0, cntpct_el0
str x0, [x19]
#endif
b el3_exit
endfunc bl31_warm_entrypoint

View File

@@ -0,0 +1,477 @@
/*
* Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <plat_macros.S>
#include <platform_def.h>
#include <arch.h>
#include <asm_macros.S>
#include <context.h>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/utils_def.h>
.globl report_unhandled_exception
.globl report_unhandled_interrupt
.globl el3_panic
.globl elx_panic
#if CRASH_REPORTING
/* ------------------------------------------------------
* The below section deals with dumping the system state
* when an unhandled exception is taken in EL3.
* The layout and the names of the registers which will
* be dumped during a unhandled exception is given below.
* ------------------------------------------------------
*/
.section .rodata.crash_prints, "aS"
print_spacer:
.asciz " = 0x"
gp_regs:
.asciz "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",\
"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",\
"x16", "x17", "x18", "x19", "x20", "x21", "x22",\
"x23", "x24", "x25", "x26", "x27", "x28", "x29", ""
el3_sys_regs:
.asciz "scr_el3", "sctlr_el3", "cptr_el3", "tcr_el3",\
"daif", "mair_el3", "spsr_el3", "elr_el3", "ttbr0_el3",\
"esr_el3", "far_el3", ""
non_el3_sys_regs:
.asciz "spsr_el1", "elr_el1", "spsr_abt", "spsr_und",\
"spsr_irq", "spsr_fiq", "sctlr_el1", "actlr_el1", "cpacr_el1",\
"csselr_el1", "sp_el1", "esr_el1", "ttbr0_el1", "ttbr1_el1",\
"mair_el1", "amair_el1", "tcr_el1", "tpidr_el1", "tpidr_el0",\
"tpidrro_el0", "par_el1", "mpidr_el1", "afsr0_el1", "afsr1_el1",\
"contextidr_el1", "vbar_el1", "cntp_ctl_el0", "cntp_cval_el0",\
"cntv_ctl_el0", "cntv_cval_el0", "cntkctl_el1", "sp_el0", "isr_el1", ""
#if CTX_INCLUDE_AARCH32_REGS
aarch32_regs:
.asciz "dacr32_el2", "ifsr32_el2", ""
#endif /* CTX_INCLUDE_AARCH32_REGS */
panic_msg:
.asciz "PANIC in EL3.\nx30"
excpt_msg:
.asciz "Unhandled Exception in EL3.\nx30"
intr_excpt_msg:
.ascii "Unhandled Interrupt Exception in EL3.\n"
x30_msg:
.asciz "x30"
excpt_msg_el:
.asciz "Unhandled Exception from EL"
/*
* Helper function to print from crash buf.
* The print loop is controlled by the buf size and
* ascii reg name list which is passed in x6. The
* function returns the crash buf address in x0.
* Clobbers : x0 - x7, sp
*/
func size_controlled_print
/* Save the lr */
mov sp, x30
/* load the crash buf address */
mrs x7, tpidr_el3
test_size_list:
/* Calculate x5 always as it will be clobbered by asm_print_hex */
mrs x5, tpidr_el3
add x5, x5, #CPU_DATA_CRASH_BUF_SIZE
/* Test whether we have reached end of crash buf */
cmp x7, x5
b.eq exit_size_print
ldrb w4, [x6]
/* Test whether we are at end of list */
cbz w4, exit_size_print
mov x4, x6
/* asm_print_str updates x4 to point to next entry in list */
bl asm_print_str
/* x0 = number of symbols printed + 1 */
sub x0, x4, x6
/* update x6 with the updated list pointer */
mov x6, x4
bl print_alignment
ldr x4, [x7], #REGSZ
bl asm_print_hex
bl asm_print_newline
b test_size_list
exit_size_print:
mov x30, sp
ret
endfunc size_controlled_print
/* -----------------------------------------------------
* This function calculates and prints required number
* of space characters followed by "= 0x", based on the
* length of ascii register name.
* x0: length of ascii register name + 1
* ------------------------------------------------------
*/
func print_alignment
/* The minimum ascii length is 3, e.g. for "x0" */
adr x4, print_spacer - 3
add x4, x4, x0
b asm_print_str
endfunc print_alignment
/*
* Helper function to store x8 - x15 registers to
* the crash buf. The system registers values are
* copied to x8 to x15 by the caller which are then
* copied to the crash buf by this function.
* x0 points to the crash buf. It then calls
* size_controlled_print to print to console.
* Clobbers : x0 - x7, sp
*/
func str_in_crash_buf_print
/* restore the crash buf address in x0 */
mrs x0, tpidr_el3
stp x8, x9, [x0]
stp x10, x11, [x0, #REGSZ * 2]
stp x12, x13, [x0, #REGSZ * 4]
stp x14, x15, [x0, #REGSZ * 6]
b size_controlled_print
endfunc str_in_crash_buf_print
/* ------------------------------------------------------
* This macro calculates the offset to crash buf from
* cpu_data and stores it in tpidr_el3. It also saves x0
* and x1 in the crash buf by using sp as a temporary
* register.
* ------------------------------------------------------
*/
.macro prepare_crash_buf_save_x0_x1
/* we can corrupt this reg to free up x0 */
mov sp, x0
/* tpidr_el3 contains the address to cpu_data structure */
mrs x0, tpidr_el3
/* Calculate the Crash buffer offset in cpu_data */
add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
/* Store crash buffer address in tpidr_el3 */
msr tpidr_el3, x0
str x1, [x0, #REGSZ]
mov x1, sp
str x1, [x0]
.endm
/* -----------------------------------------------------
* This function allows to report a crash (if crash
* reporting is enabled) when an unhandled exception
* occurs. It prints the CPU state via the crash console
* making use of the crash buf. This function will
* not return.
* -----------------------------------------------------
*/
func report_unhandled_exception
prepare_crash_buf_save_x0_x1
adr x0, excpt_msg
mov sp, x0
/* This call will not return */
b do_crash_reporting
endfunc report_unhandled_exception
/* -----------------------------------------------------
* This function allows to report a crash (if crash
* reporting is enabled) when an unhandled interrupt
* occurs. It prints the CPU state via the crash console
* making use of the crash buf. This function will
* not return.
* -----------------------------------------------------
*/
func report_unhandled_interrupt
prepare_crash_buf_save_x0_x1
adr x0, intr_excpt_msg
mov sp, x0
/* This call will not return */
b do_crash_reporting
endfunc report_unhandled_interrupt
/* -----------------------------------------------------
* This function allows to report a crash from the lower
* exception level (if crash reporting is enabled) when
* panic() is invoked from C Runtime.
* It prints the CPU state via the crash console making
* use of 'cpu_context' structure where general purpose
* registers are saved and the crash buf.
* This function will not return.
*
* x0: Exception level
* -----------------------------------------------------
*/
func elx_panic
msr spsel, #MODE_SP_ELX
mov x8, x0
/* Print the crash message */
adr x4, excpt_msg_el
bl asm_print_str
/* Print exception level */
add x0, x8, #'0'
bl plat_crash_console_putc
bl asm_print_newline
/* Report x0 - x29 values stored in 'gpregs_ctx' structure */
/* Store the ascii list pointer in x6 */
adr x6, gp_regs
add x7, sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0
print_next:
ldrb w4, [x6]
/* Test whether we are at end of list */
cbz w4, print_x30
mov x4, x6
/* asm_print_str updates x4 to point to next entry in list */
bl asm_print_str
/* x0 = number of symbols printed + 1 */
sub x0, x4, x6
/* Update x6 with the updated list pointer */
mov x6, x4
bl print_alignment
ldr x4, [x7], #REGSZ
bl asm_print_hex
bl asm_print_newline
b print_next
print_x30:
adr x4, x30_msg
bl asm_print_str
/* Print spaces to align "x30" string */
mov x0, #4
bl print_alignment
/* Report x30 */
ldr x4, [x7]
/* ----------------------------------------------------------------
* Different virtual address space size can be defined for each EL.
* Ensure that we use the proper one by reading the corresponding
* TCR_ELx register.
* ----------------------------------------------------------------
*/
cmp x8, #MODE_EL2
b.lt from_el1 /* EL1 */
mrs x2, sctlr_el2
mrs x1, tcr_el2
/* ----------------------------------------------------------------
* Check if pointer authentication is enabled at the specified EL.
* If it isn't, we can then skip stripping a PAC code.
* ----------------------------------------------------------------
*/
test_pauth:
tst x2, #(SCTLR_EnIA_BIT | SCTLR_EnIB_BIT)
b.eq no_pauth
/* Demangle address */
and x1, x1, #0x3F /* T0SZ = TCR_ELx[5:0] */
sub x1, x1, #64
neg x1, x1 /* bottom_pac_bit = 64 - T0SZ */
mov x2, #-1
lsl x2, x2, x1
bic x4, x4, x2
no_pauth:
bl asm_print_hex
bl asm_print_newline
/* tpidr_el3 contains the address to cpu_data structure */
mrs x0, tpidr_el3
/* Calculate the Crash buffer offset in cpu_data */
add x0, x0, #CPU_DATA_CRASH_BUF_OFFSET
/* Store crash buffer address in tpidr_el3 */
msr tpidr_el3, x0
/* Print the rest of crash dump */
b print_el3_sys_regs
from_el1:
mrs x2, sctlr_el1
mrs x1, tcr_el1
b test_pauth
endfunc elx_panic
/* -----------------------------------------------------
* This function allows to report a crash (if crash
* reporting is enabled) when panic() is invoked from
* C Runtime. It prints the CPU state via the crash
* console making use of the crash buf. This function
* will not return.
* -----------------------------------------------------
*/
func el3_panic
msr spsel, #MODE_SP_ELX
prepare_crash_buf_save_x0_x1
adr x0, panic_msg
mov sp, x0
/* Fall through to 'do_crash_reporting' */
/* ------------------------------------------------------------
* The common crash reporting functionality. It requires x0
* and x1 has already been stored in crash buf, sp points to
* crash message and tpidr_el3 contains the crash buf address.
* The function does the following:
* - Retrieve the crash buffer from tpidr_el3
* - Store x2 to x6 in the crash buffer
* - Initialise the crash console.
* - Print the crash message by using the address in sp.
* - Print x30 value to the crash console.
* - Print x0 - x7 from the crash buf to the crash console.
* - Print x8 - x29 (in groups of 8 registers) using the
* crash buf to the crash console.
* - Print el3 sys regs (in groups of 8 registers) using the
* crash buf to the crash console.
* - Print non el3 sys regs (in groups of 8 registers) using
* the crash buf to the crash console.
* ------------------------------------------------------------
*/
do_crash_reporting:
/* Retrieve the crash buf from tpidr_el3 */
mrs x0, tpidr_el3
/* Store x2 - x6, x30 in the crash buffer */
stp x2, x3, [x0, #REGSZ * 2]
stp x4, x5, [x0, #REGSZ * 4]
stp x6, x30, [x0, #REGSZ * 6]
/* Initialize the crash console */
bl plat_crash_console_init
/* Verify the console is initialized */
cbz x0, crash_panic
/* Print the crash message. sp points to the crash message */
mov x4, sp
bl asm_print_str
/* Print spaces to align "x30" string */
mov x0, #4
bl print_alignment
/* Load the crash buf address */
mrs x0, tpidr_el3
/* Report x30 first from the crash buf */
ldr x4, [x0, #REGSZ * 7]
#if ENABLE_PAUTH
/* Demangle address */
xpaci x4
#endif
bl asm_print_hex
bl asm_print_newline
/* Load the crash buf address */
mrs x0, tpidr_el3
/* Now mov x7 into crash buf */
str x7, [x0, #REGSZ * 7]
/* Report x0 - x29 values stored in crash buf */
/* Store the ascii list pointer in x6 */
adr x6, gp_regs
/* Print x0 to x7 from the crash buf */
bl size_controlled_print
/* Store x8 - x15 in crash buf and print */
bl str_in_crash_buf_print
/* Load the crash buf address */
mrs x0, tpidr_el3
/* Store the rest of gp regs and print */
stp x16, x17, [x0]
stp x18, x19, [x0, #REGSZ * 2]
stp x20, x21, [x0, #REGSZ * 4]
stp x22, x23, [x0, #REGSZ * 6]
bl size_controlled_print
/* Load the crash buf address */
mrs x0, tpidr_el3
stp x24, x25, [x0]
stp x26, x27, [x0, #REGSZ * 2]
stp x28, x29, [x0, #REGSZ * 4]
bl size_controlled_print
/* Print the el3 sys registers */
print_el3_sys_regs:
adr x6, el3_sys_regs
mrs x8, scr_el3
mrs x9, sctlr_el3
mrs x10, cptr_el3
mrs x11, tcr_el3
mrs x12, daif
mrs x13, mair_el3
mrs x14, spsr_el3
mrs x15, elr_el3
bl str_in_crash_buf_print
mrs x8, ttbr0_el3
mrs x9, esr_el3
mrs x10, far_el3
bl str_in_crash_buf_print
/* Print the non el3 sys registers */
adr x6, non_el3_sys_regs
mrs x8, spsr_el1
mrs x9, elr_el1
mrs x10, spsr_abt
mrs x11, spsr_und
mrs x12, spsr_irq
mrs x13, spsr_fiq
mrs x14, sctlr_el1
mrs x15, actlr_el1
bl str_in_crash_buf_print
mrs x8, cpacr_el1
mrs x9, csselr_el1
mrs x10, sp_el1
mrs x11, esr_el1
mrs x12, ttbr0_el1
mrs x13, ttbr1_el1
mrs x14, mair_el1
mrs x15, amair_el1
bl str_in_crash_buf_print
mrs x8, tcr_el1
mrs x9, tpidr_el1
mrs x10, tpidr_el0
mrs x11, tpidrro_el0
mrs x12, par_el1
mrs x13, mpidr_el1
mrs x14, afsr0_el1
mrs x15, afsr1_el1
bl str_in_crash_buf_print
mrs x8, contextidr_el1
mrs x9, vbar_el1
mrs x10, cntp_ctl_el0
mrs x11, cntp_cval_el0
mrs x12, cntv_ctl_el0
mrs x13, cntv_cval_el0
mrs x14, cntkctl_el1
mrs x15, sp_el0
bl str_in_crash_buf_print
mrs x8, isr_el1
bl str_in_crash_buf_print
#if CTX_INCLUDE_AARCH32_REGS
/* Print the AArch32 registers */
adr x6, aarch32_regs
mrs x8, dacr32_el2
mrs x9, ifsr32_el2
bl str_in_crash_buf_print
#endif /* CTX_INCLUDE_AARCH32_REGS */
/* Get the cpu specific registers to report */
bl do_cpu_reg_dump
bl str_in_crash_buf_print
/* Print some platform registers */
plat_crash_print_regs
bl plat_crash_console_flush
/* Done reporting */
no_ret plat_panic_handler
endfunc el3_panic
#else /* CRASH_REPORTING */
func report_unhandled_exception
report_unhandled_interrupt:
no_ret plat_panic_handler
endfunc report_unhandled_exception
#endif /* CRASH_REPORTING */
func crash_panic
no_ret plat_panic_handler
endfunc crash_panic

View File

@@ -0,0 +1,317 @@
/*
* Copyright (c) 2018-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert_macros.S>
#include <asm_macros.S>
#include <assert_macros.S>
#include <bl31/ea_handle.h>
#include <context.h>
#include <lib/extensions/ras_arch.h>
#include <cpu_macros.S>
#include <context.h>
.globl handle_lower_el_ea_esb
.globl handle_lower_el_async_ea
.globl enter_lower_el_sync_ea
.globl enter_lower_el_async_ea
/*
* Function to delegate External Aborts synchronized by ESB instruction at EL3
* vector entry. This function assumes GP registers x0-x29 have been saved, and
* are available for use. It delegates the handling of the EA to platform
* handler, and returns only upon successfully handling the EA; otherwise
* panics. On return from this function, the original exception handler is
* expected to resume.
*/
func handle_lower_el_ea_esb
mov x0, #ERROR_EA_ESB
mrs x1, DISR_EL1
b ea_proceed
endfunc handle_lower_el_ea_esb
/*
* This function forms the tail end of Synchronous Exception entry from lower
* EL, and expects to handle Synchronous External Aborts from lower EL and CPU
* Implementation Defined Exceptions. If any other kind of exception is detected,
* then this function reports unhandled exception.
*
* Since it's part of exception vector, this function doesn't expect any GP
* registers to have been saved. It delegates the handling of the EA to platform
* handler, and upon successfully handling the EA, exits EL3; otherwise panics.
*/
func enter_lower_el_sync_ea
/*
* Explicitly save x30 so as to free up a register and to enable
* branching.
*/
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
/* Check for I/D aborts from lower EL */
cmp x30, #EC_IABORT_LOWER_EL
b.eq 1f
cmp x30, #EC_DABORT_LOWER_EL
b.eq 1f
/* Save GP registers */
stp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
stp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
stp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
/* Get the cpu_ops pointer */
bl get_cpu_ops_ptr
/* Get the cpu_ops exception handler */
ldr x0, [x0, #CPU_E_HANDLER_FUNC]
/*
* If the reserved function pointer is NULL, this CPU does not have an
* implementation defined exception handler function
*/
cbz x0, 2f
mrs x1, esr_el3
ubfx x1, x1, #ESR_EC_SHIFT, #ESR_EC_LENGTH
blr x0
b 2f
1:
/* Test for EA bit in the instruction syndrome */
mrs x30, esr_el3
tbz x30, #ESR_ISS_EABORT_EA_BIT, 3f
/*
* Save general purpose and ARMv8.3-PAuth registers (if enabled).
* If Secure Cycle Counter is not disabled in MDCR_EL3 when
* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
* Also set the PSTATE to a known state.
*/
bl prepare_el3_entry
#if ENABLE_PAUTH
/* Load and program APIAKey firmware key */
bl pauth_load_bl31_apiakey
#endif
/* Setup exception class and syndrome arguments for platform handler */
mov x0, #ERROR_EA_SYNC
mrs x1, esr_el3
bl delegate_sync_ea
/* el3_exit assumes SP_EL0 on entry */
msr spsel, #MODE_SP_EL0
b el3_exit
2:
ldp x0, x1, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
ldp x2, x3, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X2]
ldp x4, x5, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X4]
3:
/* Synchronous exceptions other than the above are assumed to be EA */
ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
no_ret report_unhandled_exception
endfunc enter_lower_el_sync_ea
/*
* This function handles SErrors from lower ELs.
*
* Since it's part of exception vector, this function doesn't expect any GP
* registers to have been saved. It delegates the handling of the EA to platform
* handler, and upon successfully handling the EA, exits EL3; otherwise panics.
*/
func enter_lower_el_async_ea
/*
* Explicitly save x30 so as to free up a register and to enable
* branching
*/
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
handle_lower_el_async_ea:
/*
* Save general purpose and ARMv8.3-PAuth registers (if enabled).
* If Secure Cycle Counter is not disabled in MDCR_EL3 when
* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
* Also set the PSTATE to a known state.
*/
bl prepare_el3_entry
#if ENABLE_PAUTH
/* Load and program APIAKey firmware key */
bl pauth_load_bl31_apiakey
#endif
/* Setup exception class and syndrome arguments for platform handler */
mov x0, #ERROR_EA_ASYNC
mrs x1, esr_el3
bl delegate_async_ea
/* el3_exit assumes SP_EL0 on entry */
msr spsel, #MODE_SP_EL0
b el3_exit
endfunc enter_lower_el_async_ea
/*
* Prelude for Synchronous External Abort handling. This function assumes that
* all GP registers have been saved by the caller.
*
* x0: EA reason
* x1: EA syndrome
*/
func delegate_sync_ea
#if RAS_EXTENSION
/*
* Check for Uncontainable error type. If so, route to the platform
* fatal error handler rather than the generic EA one.
*/
ubfx x2, x1, #EABORT_SET_SHIFT, #EABORT_SET_WIDTH
cmp x2, #ERROR_STATUS_SET_UC
b.ne 1f
/* Check fault status code */
ubfx x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
cmp x3, #SYNC_EA_FSC
b.ne 1f
no_ret plat_handle_uncontainable_ea
1:
#endif
b ea_proceed
endfunc delegate_sync_ea
/*
* Prelude for Asynchronous External Abort handling. This function assumes that
* all GP registers have been saved by the caller.
*
* x0: EA reason
* x1: EA syndrome
*/
func delegate_async_ea
#if RAS_EXTENSION
/*
* Check for Implementation Defined Syndrome. If so, skip checking
* Uncontainable error type from the syndrome as the format is unknown.
*/
tbnz x1, #SERROR_IDS_BIT, 1f
/*
* Check for Uncontainable error type. If so, route to the platform
* fatal error handler rather than the generic EA one.
*/
ubfx x2, x1, #EABORT_AET_SHIFT, #EABORT_AET_WIDTH
cmp x2, #ERROR_STATUS_UET_UC
b.ne 1f
/* Check DFSC for SError type */
ubfx x3, x1, #EABORT_DFSC_SHIFT, #EABORT_DFSC_WIDTH
cmp x3, #DFSC_SERROR
b.ne 1f
no_ret plat_handle_uncontainable_ea
1:
#endif
b ea_proceed
endfunc delegate_async_ea
/*
* Delegate External Abort handling to platform's EA handler. This function
* assumes that all GP registers have been saved by the caller.
*
* x0: EA reason
* x1: EA syndrome
*/
func ea_proceed
/*
* If the ESR loaded earlier is not zero, we were processing an EA
* already, and this is a double fault.
*/
ldr x5, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
cbz x5, 1f
no_ret plat_handle_double_fault
1:
/* Save EL3 state */
mrs x2, spsr_el3
mrs x3, elr_el3
stp x2, x3, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
/*
* Save ESR as handling might involve lower ELs, and returning back to
* EL3 from there would trample the original ESR.
*/
mrs x4, scr_el3
mrs x5, esr_el3
stp x4, x5, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
/*
* Setup rest of arguments, and call platform External Abort handler.
*
* x0: EA reason (already in place)
* x1: Exception syndrome (already in place).
* x2: Cookie (unused for now).
* x3: Context pointer.
* x4: Flags (security state from SCR for now).
*/
mov x2, xzr
mov x3, sp
ubfx x4, x4, #0, #1
/* Switch to runtime stack */
ldr x5, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
msr spsel, #MODE_SP_EL0
mov sp, x5
mov x29, x30
#if ENABLE_ASSERTIONS
/* Stash the stack pointer */
mov x28, sp
#endif
bl plat_ea_handler
#if ENABLE_ASSERTIONS
/*
* Error handling flows might involve long jumps; so upon returning from
* the platform error handler, validate that the we've completely
* unwound the stack.
*/
mov x27, sp
cmp x28, x27
ASM_ASSERT(eq)
#endif
/* Make SP point to context */
msr spsel, #MODE_SP_ELX
/* Restore EL3 state and ESR */
ldp x1, x2, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
msr spsr_el3, x1
msr elr_el3, x2
/* Restore ESR_EL3 and SCR_EL3 */
ldp x3, x4, [sp, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
msr scr_el3, x3
msr esr_el3, x4
#if ENABLE_ASSERTIONS
cmp x4, xzr
ASM_ASSERT(ne)
#endif
/* Clear ESR storage */
str xzr, [sp, #CTX_EL3STATE_OFFSET + CTX_ESR_EL3]
ret x29
endfunc ea_proceed

View File

@@ -0,0 +1,621 @@
/*
* Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <asm_macros.S>
#include <bl31/ea_handle.h>
#include <bl31/interrupt_mgmt.h>
#include <common/runtime_svc.h>
#include <context.h>
#include <el3_common_macros.S>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/smccc.h>
.globl runtime_exceptions
.globl sync_exception_sp_el0
.globl irq_sp_el0
.globl fiq_sp_el0
.globl serror_sp_el0
.globl sync_exception_sp_elx
.globl irq_sp_elx
.globl fiq_sp_elx
.globl serror_sp_elx
.globl sync_exception_aarch64
.globl irq_aarch64
.globl fiq_aarch64
.globl serror_aarch64
.globl sync_exception_aarch32
.globl irq_aarch32
.globl fiq_aarch32
.globl serror_aarch32
/*
* Macro that prepares entry to EL3 upon taking an exception.
*
* With RAS_EXTENSION, this macro synchronizes pending errors with an ESB
* instruction. When an error is thus synchronized, the handling is
* delegated to platform EA handler.
*
* Without RAS_EXTENSION, this macro synchronizes pending errors using
* a DSB, unmasks Asynchronous External Aborts and saves X30 before
* setting the flag CTX_IS_IN_EL3.
*/
.macro check_and_unmask_ea
#if RAS_EXTENSION
/* Synchronize pending External Aborts */
esb
/* Unmask the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
/*
* Explicitly save x30 so as to free up a register and to enable
* branching
*/
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
/* Check for SErrors synchronized by the ESB instruction */
mrs x30, DISR_EL1
tbz x30, #DISR_A_BIT, 1f
/*
* Save general purpose and ARMv8.3-PAuth registers (if enabled).
* If Secure Cycle Counter is not disabled in MDCR_EL3 when
* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
* Also set the PSTATE to a known state.
*/
bl prepare_el3_entry
bl handle_lower_el_ea_esb
/* Restore general purpose, PMCR_EL0 and ARMv8.3-PAuth registers */
bl restore_gp_pmcr_pauth_regs
1:
#else
/*
* For SoCs which do not implement RAS, use DSB as a barrier to
* synchronize pending external aborts.
*/
dsb sy
/* Unmask the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
/* Use ISB for the above unmask operation to take effect immediately */
isb
/*
* Refer Note 1. No need to restore X30 as both handle_sync_exception
* and handle_interrupt_exception macro which follow this macro modify
* X30 anyway.
*/
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mov x30, #1
str x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
dmb sy
#endif
.endm
#if !RAS_EXTENSION
/*
* Note 1: The explicit DSB at the entry of various exception vectors
* for handling exceptions from lower ELs can inadvertently trigger an
* SError exception in EL3 due to pending asynchronous aborts in lower
* ELs. This will end up being handled by serror_sp_elx which will
* ultimately panic and die.
* The way to workaround is to update a flag to indicate if the exception
* truly came from EL3. This flag is allocated in the cpu_context
* structure and located at offset "CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3"
* This is not a bullet proof solution to the problem at hand because
* we assume the instructions following "isb" that help to update the
* flag execute without causing further exceptions.
*/
/* ---------------------------------------------------------------------
* This macro handles Asynchronous External Aborts.
* ---------------------------------------------------------------------
*/
.macro handle_async_ea
/*
* Use a barrier to synchronize pending external aborts.
*/
dsb sy
/* Unmask the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
/* Use ISB for the above unmask operation to take effect immediately */
isb
/* Refer Note 1 */
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mov x30, #1
str x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
dmb sy
b handle_lower_el_async_ea
.endm
/*
* This macro checks if the exception was taken due to SError in EL3 or
* because of pending asynchronous external aborts from lower EL that got
* triggered due to explicit synchronization in EL3. Refer Note 1.
*/
.macro check_if_serror_from_EL3
/* Assumes SP_EL3 on entry */
str x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
ldr x30, [sp, #CTX_EL3STATE_OFFSET + CTX_IS_IN_EL3]
cbnz x30, exp_from_EL3
/* Handle asynchronous external abort from lower EL */
b handle_lower_el_async_ea
exp_from_EL3:
/* Jump to plat_handle_el3_ea which does not return */
.endm
#endif
/* ---------------------------------------------------------------------
* This macro handles Synchronous exceptions.
* Only SMC exceptions are supported.
* ---------------------------------------------------------------------
*/
.macro handle_sync_exception
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Read the timestamp value and store it in per-cpu data. The value
* will be extracted from per-cpu data by the C level SMC handler and
* saved to the PMF timestamp region.
*/
mrs x30, cntpct_el0
str x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
mrs x29, tpidr_el3
str x30, [x29, #CPU_DATA_PMF_TS0_OFFSET]
ldr x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X29]
#endif
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
/* Handle SMC exceptions separately from other synchronous exceptions */
cmp x30, #EC_AARCH32_SMC
b.eq smc_handler32
cmp x30, #EC_AARCH64_SMC
b.eq smc_handler64
/* Synchronous exceptions other than the above are assumed to be EA */
ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
b enter_lower_el_sync_ea
.endm
/* ---------------------------------------------------------------------
* This macro handles FIQ or IRQ interrupts i.e. EL3, S-EL1 and NS
* interrupts.
* ---------------------------------------------------------------------
*/
.macro handle_interrupt_exception label
/*
* Save general purpose and ARMv8.3-PAuth registers (if enabled).
* If Secure Cycle Counter is not disabled in MDCR_EL3 when
* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
* Also set the PSTATE to a known state.
*/
bl prepare_el3_entry
#if ENABLE_PAUTH
/* Load and program APIAKey firmware key */
bl pauth_load_bl31_apiakey
#endif
/* Save the EL3 system registers needed to return from this exception */
mrs x0, spsr_el3
mrs x1, elr_el3
stp x0, x1, [sp, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
/* Switch to the runtime stack i.e. SP_EL0 */
ldr x2, [sp, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
mov x20, sp
msr spsel, #MODE_SP_EL0
mov sp, x2
/*
* Find out whether this is a valid interrupt type.
* If the interrupt controller reports a spurious interrupt then return
* to where we came from.
*/
bl plat_ic_get_pending_interrupt_type
cmp x0, #INTR_TYPE_INVAL
b.eq interrupt_exit_\label
/*
* Get the registered handler for this interrupt type.
* A NULL return value could be 'cause of the following conditions:
*
* a. An interrupt of a type was routed correctly but a handler for its
* type was not registered.
*
* b. An interrupt of a type was not routed correctly so a handler for
* its type was not registered.
*
* c. An interrupt of a type was routed correctly to EL3, but was
* deasserted before its pending state could be read. Another
* interrupt of a different type pended at the same time and its
* type was reported as pending instead. However, a handler for this
* type was not registered.
*
* a. and b. can only happen due to a programming error. The
* occurrence of c. could be beyond the control of Trusted Firmware.
* It makes sense to return from this exception instead of reporting an
* error.
*/
bl get_interrupt_type_handler
cbz x0, interrupt_exit_\label
mov x21, x0
mov x0, #INTR_ID_UNAVAILABLE
/* Set the current security state in the 'flags' parameter */
mrs x2, scr_el3
ubfx x1, x2, #0, #1
/* Restore the reference to the 'handle' i.e. SP_EL3 */
mov x2, x20
/* x3 will point to a cookie (not used now) */
mov x3, xzr
/* Call the interrupt type handler */
blr x21
interrupt_exit_\label:
/* Return from exception, possibly in a different security state */
b el3_exit
.endm
vector_base runtime_exceptions
/* ---------------------------------------------------------------------
* Current EL with SP_EL0 : 0x0 - 0x200
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_sp_el0
#ifdef MONITOR_TRAPS
stp x29, x30, [sp, #-16]!
mrs x30, esr_el3
ubfx x30, x30, #ESR_EC_SHIFT, #ESR_EC_LENGTH
/* Check for BRK */
cmp x30, #EC_BRK
b.eq brk_handler
ldp x29, x30, [sp], #16
#endif /* MONITOR_TRAPS */
/* We don't expect any synchronous exceptions from EL3 */
b report_unhandled_exception
end_vector_entry sync_exception_sp_el0
vector_entry irq_sp_el0
/*
* EL3 code is non-reentrant. Any asynchronous exception is a serious
* error. Loop infinitely.
*/
b report_unhandled_interrupt
end_vector_entry irq_sp_el0
vector_entry fiq_sp_el0
b report_unhandled_interrupt
end_vector_entry fiq_sp_el0
vector_entry serror_sp_el0
no_ret plat_handle_el3_ea
end_vector_entry serror_sp_el0
/* ---------------------------------------------------------------------
* Current EL with SP_ELx: 0x200 - 0x400
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_sp_elx
/*
* This exception will trigger if anything went wrong during a previous
* exception entry or exit or while handling an earlier unexpected
* synchronous exception. There is a high probability that SP_EL3 is
* corrupted.
*/
b report_unhandled_exception
end_vector_entry sync_exception_sp_elx
vector_entry irq_sp_elx
b report_unhandled_interrupt
end_vector_entry irq_sp_elx
vector_entry fiq_sp_elx
b report_unhandled_interrupt
end_vector_entry fiq_sp_elx
vector_entry serror_sp_elx
#if !RAS_EXTENSION
check_if_serror_from_EL3
#endif
no_ret plat_handle_el3_ea
end_vector_entry serror_sp_elx
/* ---------------------------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_aarch64
/*
* This exception vector will be the entry point for SMCs and traps
* that are unhandled at lower ELs most commonly. SP_EL3 should point
* to a valid cpu context where the general purpose and system register
* state can be saved.
*/
apply_at_speculative_wa
check_and_unmask_ea
handle_sync_exception
end_vector_entry sync_exception_aarch64
vector_entry irq_aarch64
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception irq_aarch64
end_vector_entry irq_aarch64
vector_entry fiq_aarch64
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception fiq_aarch64
end_vector_entry fiq_aarch64
vector_entry serror_aarch64
apply_at_speculative_wa
#if RAS_EXTENSION
msr daifclr, #DAIF_ABT_BIT
b enter_lower_el_async_ea
#else
handle_async_ea
#endif
end_vector_entry serror_aarch64
/* ---------------------------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800
* ---------------------------------------------------------------------
*/
vector_entry sync_exception_aarch32
/*
* This exception vector will be the entry point for SMCs and traps
* that are unhandled at lower ELs most commonly. SP_EL3 should point
* to a valid cpu context where the general purpose and system register
* state can be saved.
*/
apply_at_speculative_wa
check_and_unmask_ea
handle_sync_exception
end_vector_entry sync_exception_aarch32
vector_entry irq_aarch32
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception irq_aarch32
end_vector_entry irq_aarch32
vector_entry fiq_aarch32
apply_at_speculative_wa
check_and_unmask_ea
handle_interrupt_exception fiq_aarch32
end_vector_entry fiq_aarch32
vector_entry serror_aarch32
apply_at_speculative_wa
#if RAS_EXTENSION
msr daifclr, #DAIF_ABT_BIT
b enter_lower_el_async_ea
#else
handle_async_ea
#endif
end_vector_entry serror_aarch32
#ifdef MONITOR_TRAPS
.section .rodata.brk_string, "aS"
brk_location:
.asciz "Error at instruction 0x"
brk_message:
.asciz "Unexpected BRK instruction with value 0x"
#endif /* MONITOR_TRAPS */
/* ---------------------------------------------------------------------
* The following code handles secure monitor calls.
* Depending upon the execution state from where the SMC has been
* invoked, it frees some general purpose registers to perform the
* remaining tasks. They involve finding the runtime service handler
* that is the target of the SMC & switching to runtime stacks (SP_EL0)
* before calling the handler.
*
* Note that x30 has been explicitly saved and can be used here
* ---------------------------------------------------------------------
*/
func smc_handler
smc_handler32:
/* Check whether aarch32 issued an SMC64 */
tbnz x0, #FUNCID_CC_SHIFT, smc_prohibited
smc_handler64:
/* NOTE: The code below must preserve x0-x4 */
/*
* Save general purpose and ARMv8.3-PAuth registers (if enabled).
* If Secure Cycle Counter is not disabled in MDCR_EL3 when
* ARMv8.5-PMU is implemented, save PMCR_EL0 and disable Cycle Counter.
* Also set the PSTATE to a known state.
*/
bl prepare_el3_entry
#if ENABLE_PAUTH
/* Load and program APIAKey firmware key */
bl pauth_load_bl31_apiakey
#endif
/*
* Populate the parameters for the SMC handler.
* We already have x0-x4 in place. x5 will point to a cookie (not used
* now). x6 will point to the context structure (SP_EL3) and x7 will
* contain flags we need to pass to the handler.
*/
mov x5, xzr
mov x6, sp
/*
* Restore the saved C runtime stack value which will become the new
* SP_EL0 i.e. EL3 runtime stack. It was saved in the 'cpu_context'
* structure prior to the last ERET from EL3.
*/
ldr x12, [x6, #CTX_EL3STATE_OFFSET + CTX_RUNTIME_SP]
/* Switch to SP_EL0 */
msr spsel, #MODE_SP_EL0
/*
* Save the SPSR_EL3, ELR_EL3, & SCR_EL3 in case there is a world
* switch during SMC handling.
* TODO: Revisit if all system registers can be saved later.
*/
mrs x16, spsr_el3
mrs x17, elr_el3
mrs x18, scr_el3
stp x16, x17, [x6, #CTX_EL3STATE_OFFSET + CTX_SPSR_EL3]
str x18, [x6, #CTX_EL3STATE_OFFSET + CTX_SCR_EL3]
/* Clear flag register */
mov x7, xzr
#if ENABLE_RME
/* Copy SCR_EL3.NSE bit to the flag to indicate caller's security */
ubfx x7, x18, #SCR_NSE_SHIFT, 1
/*
* Shift copied SCR_EL3.NSE bit by 5 to create space for
* SCR_EL3.NS bit. Bit 5 of the flag correspondes to
* the SCR_EL3.NSE bit.
*/
lsl x7, x7, #5
#endif /* ENABLE_RME */
/* Copy SCR_EL3.NS bit to the flag to indicate caller's security */
bfi x7, x18, #0, #1
mov sp, x12
/* Get the unique owning entity number */
ubfx x16, x0, #FUNCID_OEN_SHIFT, #FUNCID_OEN_WIDTH
ubfx x15, x0, #FUNCID_TYPE_SHIFT, #FUNCID_TYPE_WIDTH
orr x16, x16, x15, lsl #FUNCID_OEN_WIDTH
/* Load descriptor index from array of indices */
adrp x14, rt_svc_descs_indices
add x14, x14, :lo12:rt_svc_descs_indices
ldrb w15, [x14, x16]
/* Any index greater than 127 is invalid. Check bit 7. */
tbnz w15, 7, smc_unknown
/*
* Get the descriptor using the index
* x11 = (base + off), w15 = index
*
* handler = (base + off) + (index << log2(size))
*/
adr x11, (__RT_SVC_DESCS_START__ + RT_SVC_DESC_HANDLE)
lsl w10, w15, #RT_SVC_SIZE_LOG2
ldr x15, [x11, w10, uxtw]
/*
* Call the Secure Monitor Call handler and then drop directly into
* el3_exit() which will program any remaining architectural state
* prior to issuing the ERET to the desired lower EL.
*/
#if DEBUG
cbz x15, rt_svc_fw_critical_error
#endif
blr x15
b el3_exit
smc_unknown:
/*
* Unknown SMC call. Populate return value with SMC_UNK and call
* el3_exit() which will restore the remaining architectural state
* i.e., SYS, GP and PAuth registers(if any) prior to issuing the ERET
* to the desired lower EL.
*/
mov x0, #SMC_UNK
str x0, [x6, #CTX_GPREGS_OFFSET + CTX_GPREG_X0]
b el3_exit
smc_prohibited:
restore_ptw_el1_sys_regs
ldp x28, x29, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_X28]
ldr x30, [sp, #CTX_GPREGS_OFFSET + CTX_GPREG_LR]
mov x0, #SMC_UNK
exception_return
#if DEBUG
rt_svc_fw_critical_error:
/* Switch to SP_ELx */
msr spsel, #MODE_SP_ELX
no_ret report_unhandled_exception
#endif
endfunc smc_handler
/* ---------------------------------------------------------------------
* The following code handles exceptions caused by BRK instructions.
* Following a BRK instruction, the only real valid cause of action is
* to print some information and panic, as the code that caused it is
* likely in an inconsistent internal state.
*
* This is initially intended to be used in conjunction with
* __builtin_trap.
* ---------------------------------------------------------------------
*/
#ifdef MONITOR_TRAPS
func brk_handler
/* Extract the ISS */
mrs x10, esr_el3
ubfx x10, x10, #ESR_ISS_SHIFT, #ESR_ISS_LENGTH
/* Ensure the console is initialized */
bl plat_crash_console_init
adr x4, brk_location
bl asm_print_str
mrs x4, elr_el3
bl asm_print_hex
bl asm_print_newline
adr x4, brk_message
bl asm_print_str
mov x4, x10
mov x5, #28
bl asm_print_hex_bits
bl asm_print_newline
no_ret plat_panic_handler
endfunc brk_handler
#endif /* MONITOR_TRAPS */

View File

@@ -0,0 +1,195 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(bl31_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = BL31_BASE, LENGTH = BL31_LIMIT - BL31_BASE
#if SEPARATE_NOBITS_REGION
NOBITS (rw!a): ORIGIN = BL31_NOBITS_BASE, LENGTH = BL31_NOBITS_LIMIT - BL31_NOBITS_BASE
#else
#define NOBITS RAM
#endif
}
#ifdef PLAT_EXTRA_LD_SCRIPT
#include <plat.ld.S>
#endif
SECTIONS
{
. = BL31_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL31_BASE address is not aligned on a page boundary.")
__BL31_START__ = .;
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
*bl31_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(SORT(.text*)))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
/* Place pubsub sections for events */
. = ALIGN(8);
#include <lib/el3_runtime/pubsub_events.h>
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
ro . : {
__RO_START__ = .;
*bl31_entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
/* Place pubsub sections for events */
. = ALIGN(8);
#include <lib/el3_runtime/pubsub_events.h>
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as read-only,
* executable. No RW data from the next section must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
#if SPM_MM
#ifndef SPM_SHIM_EXCEPTIONS_VMA
#define SPM_SHIM_EXCEPTIONS_VMA RAM
#endif
/*
* Exception vectors of the SPM shim layer. They must be aligned to a 2K
* address, but we need to place them in a separate page so that we can set
* individual permissions to them, so the actual alignment needed is 4K.
*
* There's no need to include this into the RO section of BL31 because it
* doesn't need to be accessed by BL31.
*/
spm_shim_exceptions : ALIGN(PAGE_SIZE) {
__SPM_SHIM_EXCEPTIONS_START__ = .;
*(.spm_shim_exceptions)
. = ALIGN(PAGE_SIZE);
__SPM_SHIM_EXCEPTIONS_END__ = .;
} >SPM_SHIM_EXCEPTIONS_VMA AT>RAM
PROVIDE(__SPM_SHIM_EXCEPTIONS_LMA__ = LOADADDR(spm_shim_exceptions));
. = LOADADDR(spm_shim_exceptions) + SIZEOF(spm_shim_exceptions);
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
RELA_SECTION >RAM
#ifdef BL31_PROGBITS_LIMIT
ASSERT(. <= BL31_PROGBITS_LIMIT, "BL31 progbits has exceeded its limit.")
#endif
#if SEPARATE_NOBITS_REGION
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
. = ALIGN(PAGE_SIZE);
__RW_END__ = .;
__BL31_END__ = .;
ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
. = BL31_NOBITS_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL31 NOBITS base address is not aligned on a page boundary.")
__NOBITS_START__ = .;
#endif
STACK_SECTION >NOBITS
BSS_SECTION >NOBITS
XLAT_TABLE_SECTION >NOBITS
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory
*
* Each lock's data is contiguous and fully allocated by the compiler
*/
*(bakery_lock)
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >NOBITS
#endif
#if SEPARATE_NOBITS_REGION
/*
* Define a linker symbol to mark end of the NOBITS memory area for this
* image.
*/
__NOBITS_END__ = .;
ASSERT(. <= BL31_NOBITS_LIMIT, "BL31 NOBITS region has exceeded its limit.")
#else
/*
* Define a linker symbol to mark end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL31_END__ = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
}
ASSERT(. <= BL31_LIMIT, "BL31 image has exceeded its limit.")
#endif
}

View File

@@ -0,0 +1,170 @@
#
# Copyright (c) 2013-2022, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
################################################################################
# Include Makefile for the SPM-MM implementation
################################################################################
ifeq (${SUPPORT_UNKNOWN_MPID},1)
ifeq (${DEBUG},0)
$(warning WARNING: SUPPORT_UNKNOWN_MPID enabled)
endif
endif
ifeq (${SPM_MM},1)
ifeq (${EL3_EXCEPTION_HANDLING},0)
$(error EL3_EXCEPTION_HANDLING must be 1 for SPM-MM support)
else
$(info Including SPM Management Mode (MM) makefile)
include services/std_svc/spm/common/spm.mk
include services/std_svc/spm/spm_mm/spm_mm.mk
endif
endif
include lib/extensions/amu/amu.mk
include lib/mpmm/mpmm.mk
ifeq (${SPMC_AT_EL3},1)
$(warning "EL3 SPMC is an experimental feature")
$(info Including EL3 SPMC makefile)
include services/std_svc/spm/common/spm.mk
include services/std_svc/spm/el3_spmc/spmc.mk
endif
include lib/psci/psci_lib.mk
BL31_SOURCES += bl31/bl31_main.c \
bl31/interrupt_mgmt.c \
bl31/aarch64/bl31_entrypoint.S \
bl31/aarch64/crash_reporting.S \
bl31/aarch64/ea_delegate.S \
bl31/aarch64/runtime_exceptions.S \
bl31/bl31_context_mgmt.c \
common/runtime_svc.c \
lib/cpus/aarch64/dsu_helpers.S \
plat/common/aarch64/platform_mp_stack.S \
services/arm_arch_svc/arm_arch_svc_setup.c \
services/std_svc/std_svc_setup.c \
${PSCI_LIB_SOURCES} \
${SPMD_SOURCES} \
${SPM_MM_SOURCES} \
${SPMC_SOURCES} \
${SPM_SOURCES}
ifeq (${DISABLE_MTPMU},1)
BL31_SOURCES += lib/extensions/mtpmu/aarch64/mtpmu.S
endif
ifeq (${ENABLE_PMF}, 1)
BL31_SOURCES += lib/pmf/pmf_main.c
endif
include lib/debugfs/debugfs.mk
ifeq (${USE_DEBUGFS},1)
BL31_SOURCES += $(DEBUGFS_SRCS)
endif
ifeq (${EL3_EXCEPTION_HANDLING},1)
BL31_SOURCES += bl31/ehf.c
endif
ifeq (${SDEI_SUPPORT},1)
ifeq (${EL3_EXCEPTION_HANDLING},0)
$(error EL3_EXCEPTION_HANDLING must be 1 for SDEI support)
endif
BL31_SOURCES += services/std_svc/sdei/sdei_dispatch.S \
services/std_svc/sdei/sdei_event.c \
services/std_svc/sdei/sdei_intr_mgmt.c \
services/std_svc/sdei/sdei_main.c \
services/std_svc/sdei/sdei_state.c
endif
ifeq (${TRNG_SUPPORT},1)
BL31_SOURCES += services/std_svc/trng/trng_main.c \
services/std_svc/trng/trng_entropy_pool.c
endif
ifeq (${ENABLE_SPE_FOR_LOWER_ELS},1)
BL31_SOURCES += lib/extensions/spe/spe.c
endif
ifeq (${ENABLE_AMU},1)
BL31_SOURCES += ${AMU_SOURCES}
endif
ifeq (${ENABLE_MPMM},1)
BL31_SOURCES += ${MPMM_SOURCES}
endif
ifeq (${ENABLE_SME_FOR_NS},1)
BL31_SOURCES += lib/extensions/sme/sme.c
BL31_SOURCES += lib/extensions/sve/sve.c
else
ifeq (${ENABLE_SVE_FOR_NS},1)
BL31_SOURCES += lib/extensions/sve/sve.c
endif
endif
ifeq (${ENABLE_MPAM_FOR_LOWER_ELS},1)
BL31_SOURCES += lib/extensions/mpam/mpam.c
endif
ifeq (${ENABLE_TRBE_FOR_NS},1)
BL31_SOURCES += lib/extensions/trbe/trbe.c
endif
ifeq (${ENABLE_BRBE_FOR_NS},1)
BL31_SOURCES += lib/extensions/brbe/brbe.c
endif
ifeq (${ENABLE_SYS_REG_TRACE_FOR_NS},1)
BL31_SOURCES += lib/extensions/sys_reg_trace/aarch64/sys_reg_trace.c
endif
ifeq (${ENABLE_TRF_FOR_NS},1)
BL31_SOURCES += lib/extensions/trf/aarch64/trf.c
endif
ifeq (${WORKAROUND_CVE_2017_5715},1)
BL31_SOURCES += lib/cpus/aarch64/wa_cve_2017_5715_bpiall.S \
lib/cpus/aarch64/wa_cve_2017_5715_mmu.S
endif
ifeq ($(SMC_PCI_SUPPORT),1)
BL31_SOURCES += services/std_svc/pci_svc.c
endif
ifeq (${ENABLE_RME},1)
include lib/gpt_rme/gpt_rme.mk
BL31_SOURCES += ${GPT_LIB_SRCS} \
${RMMD_SOURCES}
endif
ifeq ($(FEATURE_DETECTION),1)
BL31_SOURCES += common/feat_detect.c
endif
BL31_LINKERFILE := bl31/bl31.ld.S
# Flag used to indicate if Crash reporting via console should be included
# in BL31. This defaults to being present in DEBUG builds only
ifndef CRASH_REPORTING
CRASH_REPORTING := $(DEBUG)
endif
$(eval $(call assert_booleans,\
$(sort \
CRASH_REPORTING \
EL3_EXCEPTION_HANDLING \
SDEI_SUPPORT \
)))
$(eval $(call add_defines,\
$(sort \
CRASH_REPORTING \
EL3_EXCEPTION_HANDLING \
SDEI_SUPPORT \
)))

View File

@@ -0,0 +1,66 @@
/*
* Copyright (c) 2013-2021, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bl31/bl31.h>
#include <common/bl_common.h>
#include <context.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/el3_runtime/cpu_data.h>
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the calling CPU that was set as the context for the specified security
* state. NULL is returned if no such structure has been specified.
******************************************************************************/
void *cm_get_context(uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
return get_cpu_data(cpu_context[get_cpu_context_index(security_state)]);
}
/*******************************************************************************
* This function sets the pointer to the current 'cpu_context' structure for the
* specified security state for the calling CPU
******************************************************************************/
void cm_set_context(void *context, uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
set_cpu_data(cpu_context[get_cpu_context_index(security_state)],
context);
}
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the CPU identified by `cpu_idx` that was set as the context for the
* specified security state. NULL is returned if no such structure has been
* specified.
******************************************************************************/
void *cm_get_context_by_index(unsigned int cpu_idx,
unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
return get_cpu_data_by_index(cpu_idx,
cpu_context[get_cpu_context_index(security_state)]);
}
/*******************************************************************************
* This function sets the pointer to the current 'cpu_context' structure for the
* specified security state for the CPU identified by CPU index.
******************************************************************************/
void cm_set_context_by_index(unsigned int cpu_idx, void *context,
unsigned int security_state)
{
assert(sec_state_is_valid(security_state));
set_cpu_data_by_index(cpu_idx,
cpu_context[get_cpu_context_index(security_state)],
context);
}

View File

@@ -0,0 +1,298 @@
/*
* Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <arch.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <bl31/bl31.h>
#include <bl31/ehf.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/feat_detect.h>
#include <common/runtime_svc.h>
#include <drivers/console.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/pmf/pmf.h>
#include <lib/runtime_instr.h>
#include <plat/common/platform.h>
#include <services/std_svc.h>
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_REGISTER_SERVICE_SMC(rt_instr_svc, PMF_RT_INSTR_SVC_ID,
RT_INSTR_TOTAL_IDS, PMF_STORE_ENABLE)
#endif
/*******************************************************************************
* This function pointer is used to initialise the BL32 image. It's initialized
* by SPD calling bl31_register_bl32_init after setting up all things necessary
* for SP execution. In cases where both SPD and SP are absent, or when SPD
* finds it impossible to execute SP, this pointer is left as NULL
******************************************************************************/
static int32_t (*bl32_init)(void);
/*****************************************************************************
* Function used to initialise RMM if RME is enabled
*****************************************************************************/
#if ENABLE_RME
static int32_t (*rmm_init)(void);
#endif
/*******************************************************************************
* Variable to indicate whether next image to execute after BL31 is BL33
* (non-secure & default) or BL32 (secure).
******************************************************************************/
static uint32_t next_image_type = NON_SECURE;
#ifdef SUPPORT_UNKNOWN_MPID
/*
* Flag to know whether an unsupported MPID has been detected. To avoid having it
* landing on the .bss section, it is initialized to a non-zero value, this way
* we avoid potential WAW hazards during system bring up.
* */
volatile uint32_t unsupported_mpid_flag = 1;
#endif
/*
* Implement the ARM Standard Service function to get arguments for a
* particular service.
*/
uintptr_t get_arm_std_svc_args(unsigned int svc_mask)
{
/* Setup the arguments for PSCI Library */
DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, bl31_warm_entrypoint);
/* PSCI is the only ARM Standard Service implemented */
assert(svc_mask == PSCI_FID_MASK);
return (uintptr_t)&psci_args;
}
/*******************************************************************************
* Simple function to initialise all BL31 helper libraries.
******************************************************************************/
void __init bl31_lib_init(void)
{
cm_init();
}
/*******************************************************************************
* Setup function for BL31.
******************************************************************************/
void bl31_setup(u_register_t arg0, u_register_t arg1, u_register_t arg2,
u_register_t arg3)
{
/* Perform early platform-specific setup */
bl31_early_platform_setup2(arg0, arg1, arg2, arg3);
/* Perform late platform-specific setup */
bl31_plat_arch_setup();
#if ENABLE_FEAT_HCX
/*
* Assert that FEAT_HCX is supported on this system, without this check
* an exception would occur during context save/restore if enabled but
* not supported.
*/
assert(is_feat_hcx_present());
#endif /* ENABLE_FEAT_HCX */
#if CTX_INCLUDE_PAUTH_REGS
/*
* Assert that the ARMv8.3-PAuth registers are present or an access
* fault will be triggered when they are being saved or restored.
*/
assert(is_armv8_3_pauth_present());
#endif /* CTX_INCLUDE_PAUTH_REGS */
}
/*******************************************************************************
* BL31 is responsible for setting up the runtime services for the primary cpu
* before passing control to the bootloader or an Operating System. This
* function calls runtime_svc_init() which initializes all registered runtime
* services. The run time services would setup enough context for the core to
* switch to the next exception level. When this function returns, the core will
* switch to the programmed exception level via an ERET.
******************************************************************************/
void bl31_main(void)
{
NOTICE("BL31: %s\n", version_string);
NOTICE("BL31: %s\n", build_message);
#if FEATURE_DETECTION
/* Detect if features enabled during compilation are supported by PE. */
detect_arch_features();
#endif /* FEATURE_DETECTION */
#ifdef SUPPORT_UNKNOWN_MPID
if (unsupported_mpid_flag == 0) {
NOTICE("Unsupported MPID detected!\n");
}
#endif
/* Perform platform setup in BL31 */
bl31_platform_setup();
/* Initialise helper libraries */
bl31_lib_init();
#if EL3_EXCEPTION_HANDLING
INFO("BL31: Initialising Exception Handling Framework\n");
ehf_init();
#endif
/* Initialize the runtime services e.g. psci. */
INFO("BL31: Initializing runtime services\n");
runtime_svc_init();
/*
* All the cold boot actions on the primary cpu are done. We now need to
* decide which is the next image and how to execute it.
* If the SPD runtime service is present, it would want to pass control
* to BL32 first in S-EL1. In that case, SPD would have registered a
* function to initialize bl32 where it takes responsibility of entering
* S-EL1 and returning control back to bl31_main. Similarly, if RME is
* enabled and a function is registered to initialize RMM, control is
* transferred to RMM in R-EL2. After RMM initialization, control is
* returned back to bl31_main. Once this is done we can prepare entry
* into BL33 as normal.
*/
/*
* If SPD had registered an init hook, invoke it.
*/
if (bl32_init != NULL) {
INFO("BL31: Initializing BL32\n");
int32_t rc = (*bl32_init)();
if (rc == 0) {
WARN("BL31: BL32 initialization failed\n");
}
}
/*
* If RME is enabled and init hook is registered, initialize RMM
* in R-EL2.
*/
#if ENABLE_RME
if (rmm_init != NULL) {
INFO("BL31: Initializing RMM\n");
int32_t rc = (*rmm_init)();
if (rc == 0) {
WARN("BL31: RMM initialization failed\n");
}
}
#endif
/*
* We are ready to enter the next EL. Prepare entry into the image
* corresponding to the desired security state after the next ERET.
*/
bl31_prepare_next_image_entry();
console_flush();
/*
* Perform any platform specific runtime setup prior to cold boot exit
* from BL31
*/
bl31_plat_runtime_setup();
#ifdef FPGA
/* In FPGA stage, keep console enable for debug */
console_switch_state(CONSOLE_FLAG_BOOT);
#endif
}
/*******************************************************************************
* Accessor functions to help runtime services decide which image should be
* executed after BL31. This is BL33 or the non-secure bootloader image by
* default but the Secure payload dispatcher could override this by requesting
* an entry into BL32 (Secure payload) first. If it does so then it should use
* the same API to program an entry into BL33 once BL32 initialisation is
* complete.
******************************************************************************/
void bl31_set_next_image_type(uint32_t security_state)
{
assert(sec_state_is_valid(security_state));
next_image_type = security_state;
}
uint32_t bl31_get_next_image_type(void)
{
return next_image_type;
}
/*******************************************************************************
* This function programs EL3 registers and performs other setup to enable entry
* into the next image after BL31 at the next ERET.
******************************************************************************/
void __init bl31_prepare_next_image_entry(void)
{
entry_point_info_t *next_image_info;
uint32_t image_type;
#if CTX_INCLUDE_AARCH32_REGS
/*
* Ensure that the build flag to save AArch32 system registers in CPU
* context is not set for AArch64-only platforms.
*/
if (el_implemented(1) == EL_IMPL_A64ONLY) {
ERROR("EL1 supports AArch64-only. Please set build flag "
"CTX_INCLUDE_AARCH32_REGS = 0\n");
panic();
}
#endif
/* Determine which image to execute next */
image_type = bl31_get_next_image_type();
/* Program EL3 registers to enable entry into the next EL */
next_image_info = bl31_plat_get_next_image_ep_info(image_type);
assert(next_image_info != NULL);
assert(image_type == GET_SECURITY_STATE(next_image_info->h.attr));
INFO("BL31: Preparing for EL3 exit to %s world\n",
(image_type == SECURE) ? "secure" : "normal");
print_entry_point_info(next_image_info);
cm_init_my_context(next_image_info);
/*
* If we are entering the Non-secure world, use
* 'cm_prepare_el3_exit_ns' to exit.
*/
if (image_type == NON_SECURE) {
cm_prepare_el3_exit_ns();
} else {
cm_prepare_el3_exit(image_type);
}
}
/*******************************************************************************
* This function initializes the pointer to BL32 init function. This is expected
* to be called by the SPD after it finishes all its initialization
******************************************************************************/
void bl31_register_bl32_init(int32_t (*func)(void))
{
bl32_init = func;
}
#if ENABLE_RME
/*******************************************************************************
* This function initializes the pointer to RMM init function. This is expected
* to be called by the RMMD after it finishes all its initialization
******************************************************************************/
void bl31_register_rmm_init(int32_t (*func)(void))
{
rmm_init = func;
}
#endif

View File

@@ -0,0 +1,526 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*
* Exception handlers at EL3, their priority levels, and management.
*/
#include <assert.h>
#include <stdbool.h>
#include <bl31/ehf.h>
#include <bl31/interrupt_mgmt.h>
#include <context.h>
#include <common/debug.h>
#include <drivers/arm/gic_common.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/el3_runtime/pubsub_events.h>
#include <plat/common/platform.h>
/* Output EHF logs as verbose */
#define EHF_LOG(...) VERBOSE("EHF: " __VA_ARGS__)
#define EHF_INVALID_IDX (-1)
/* For a valid handler, return the actual function pointer; otherwise, 0. */
#define RAW_HANDLER(h) \
((ehf_handler_t) ((((h) & EHF_PRI_VALID_) != 0U) ? \
((h) & ~EHF_PRI_VALID_) : 0U))
#define PRI_BIT(idx) (((ehf_pri_bits_t) 1u) << (idx))
/*
* Convert index into secure priority using the platform-defined priority bits
* field.
*/
#define IDX_TO_PRI(idx) \
((((unsigned) idx) << (7u - exception_data.pri_bits)) & 0x7fU)
/* Check whether a given index is valid */
#define IS_IDX_VALID(idx) \
((exception_data.ehf_priorities[idx].ehf_handler & EHF_PRI_VALID_) != 0U)
/* Returns whether given priority is in secure priority range */
#define IS_PRI_SECURE(pri) (((pri) & 0x80U) == 0U)
/* To be defined by the platform */
extern const ehf_priorities_t exception_data;
/* Translate priority to the index in the priority array */
static unsigned int pri_to_idx(unsigned int priority)
{
unsigned int idx;
idx = EHF_PRI_TO_IDX(priority, exception_data.pri_bits);
assert(idx < exception_data.num_priorities);
assert(IS_IDX_VALID(idx));
return idx;
}
/* Return whether there are outstanding priority activation */
static bool has_valid_pri_activations(pe_exc_data_t *pe_data)
{
return pe_data->active_pri_bits != 0U;
}
static pe_exc_data_t *this_cpu_data(void)
{
return &get_cpu_data(ehf_data);
}
/*
* Return the current priority index of this CPU. If no priority is active,
* return EHF_INVALID_IDX.
*/
static int get_pe_highest_active_idx(pe_exc_data_t *pe_data)
{
if (!has_valid_pri_activations(pe_data))
return EHF_INVALID_IDX;
/* Current priority is the right-most bit */
return (int) __builtin_ctz(pe_data->active_pri_bits);
}
/*
* Mark priority active by setting the corresponding bit in active_pri_bits and
* programming the priority mask.
*
* This API is to be used as part of delegating to lower ELs other than for
* interrupts; e.g. while handling synchronous exceptions.
*
* This API is expected to be invoked before restoring context (Secure or
* Non-secure) in preparation for the respective dispatch.
*/
void ehf_activate_priority(unsigned int priority)
{
int cur_pri_idx;
unsigned int old_mask, run_pri, idx;
pe_exc_data_t *pe_data = this_cpu_data();
/*
* Query interrupt controller for the running priority, or idle priority
* if no interrupts are being handled. The requested priority must be
* less (higher priority) than the active running priority.
*/
run_pri = plat_ic_get_running_priority();
if (priority >= run_pri) {
ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
run_pri, priority);
panic();
}
/*
* If there were priority activations already, the requested priority
* must be less (higher priority) than the current highest priority
* activation so far.
*/
cur_pri_idx = get_pe_highest_active_idx(pe_data);
idx = pri_to_idx(priority);
if ((cur_pri_idx != EHF_INVALID_IDX) &&
(idx >= ((unsigned int) cur_pri_idx))) {
ERROR("Activation priority mismatch: req=0x%x current=0x%x\n",
priority, IDX_TO_PRI(cur_pri_idx));
panic();
}
/* Set the bit corresponding to the requested priority */
pe_data->active_pri_bits |= PRI_BIT(idx);
/*
* Program priority mask for the activated level. Check that the new
* priority mask is setting a higher priority level than the existing
* mask.
*/
old_mask = plat_ic_set_priority_mask(priority);
if (priority >= old_mask) {
ERROR("Requested priority (0x%x) lower than Priority Mask (0x%x)\n",
priority, old_mask);
panic();
}
/*
* If this is the first activation, save the priority mask. This will be
* restored after the last deactivation.
*/
if (cur_pri_idx == EHF_INVALID_IDX)
pe_data->init_pri_mask = (uint8_t) old_mask;
EHF_LOG("activate prio=%d\n", get_pe_highest_active_idx(pe_data));
}
/*
* Mark priority inactive by clearing the corresponding bit in active_pri_bits,
* and programming the priority mask.
*
* This API is expected to be used as part of delegating to to lower ELs other
* than for interrupts; e.g. while handling synchronous exceptions.
*
* This API is expected to be invoked after saving context (Secure or
* Non-secure), having concluded the respective dispatch.
*/
void ehf_deactivate_priority(unsigned int priority)
{
int cur_pri_idx;
pe_exc_data_t *pe_data = this_cpu_data();
unsigned int old_mask, run_pri, idx;
/*
* Query interrupt controller for the running priority, or idle priority
* if no interrupts are being handled. The requested priority must be
* less (higher priority) than the active running priority.
*/
run_pri = plat_ic_get_running_priority();
if (priority >= run_pri) {
ERROR("Running priority higher (0x%x) than requested (0x%x)\n",
run_pri, priority);
panic();
}
/*
* Deactivation is allowed only when there are priority activations, and
* the deactivation priority level must match the current activated
* priority.
*/
cur_pri_idx = get_pe_highest_active_idx(pe_data);
idx = pri_to_idx(priority);
if ((cur_pri_idx == EHF_INVALID_IDX) ||
(idx != ((unsigned int) cur_pri_idx))) {
ERROR("Deactivation priority mismatch: req=0x%x current=0x%x\n",
priority, IDX_TO_PRI(cur_pri_idx));
panic();
}
/* Clear bit corresponding to highest priority */
pe_data->active_pri_bits &= (pe_data->active_pri_bits - 1u);
/*
* Restore priority mask corresponding to the next priority, or the
* one stashed earlier if there are no more to deactivate.
*/
cur_pri_idx = get_pe_highest_active_idx(pe_data);
if (cur_pri_idx == EHF_INVALID_IDX)
old_mask = plat_ic_set_priority_mask(pe_data->init_pri_mask);
else
old_mask = plat_ic_set_priority_mask(priority);
if (old_mask > priority) {
ERROR("Deactivation priority (0x%x) lower than Priority Mask (0x%x)\n",
priority, old_mask);
panic();
}
EHF_LOG("deactivate prio=%d\n", get_pe_highest_active_idx(pe_data));
}
/*
* After leaving Non-secure world, stash current Non-secure Priority Mask, and
* set Priority Mask to the highest Non-secure priority so that Non-secure
* interrupts cannot preempt Secure execution.
*
* If the current running priority is in the secure range, or if there are
* outstanding priority activations, this function does nothing.
*
* This function subscribes to the 'cm_exited_normal_world' event published by
* the Context Management Library.
*/
static void *ehf_exited_normal_world(const void *arg)
{
unsigned int run_pri;
pe_exc_data_t *pe_data = this_cpu_data();
/* If the running priority is in the secure range, do nothing */
run_pri = plat_ic_get_running_priority();
if (IS_PRI_SECURE(run_pri))
return NULL;
/* Do nothing if there are explicit activations */
if (has_valid_pri_activations(pe_data))
return NULL;
assert(pe_data->ns_pri_mask == 0u);
pe_data->ns_pri_mask =
(uint8_t) plat_ic_set_priority_mask(GIC_HIGHEST_NS_PRIORITY);
/* The previous Priority Mask is not expected to be in secure range */
if (IS_PRI_SECURE(pe_data->ns_pri_mask)) {
ERROR("Priority Mask (0x%x) already in secure range\n",
pe_data->ns_pri_mask);
panic();
}
EHF_LOG("Priority Mask: 0x%x => 0x%x\n", pe_data->ns_pri_mask,
GIC_HIGHEST_NS_PRIORITY);
return NULL;
}
/*
* Conclude Secure execution and prepare for return to Non-secure world. Restore
* the Non-secure Priority Mask previously stashed upon leaving Non-secure
* world.
*
* If there the current running priority is in the secure range, or if there are
* outstanding priority activations, this function does nothing.
*
* This function subscribes to the 'cm_entering_normal_world' event published by
* the Context Management Library.
*/
static void *ehf_entering_normal_world(const void *arg)
{
unsigned int old_pmr, run_pri;
pe_exc_data_t *pe_data = this_cpu_data();
/* If the running priority is in the secure range, do nothing */
run_pri = plat_ic_get_running_priority();
if (IS_PRI_SECURE(run_pri))
return NULL;
/*
* If there are explicit activations, do nothing. The Priority Mask will
* be restored upon the last deactivation.
*/
if (has_valid_pri_activations(pe_data))
return NULL;
/* Do nothing if we don't have a valid Priority Mask to restore */
if (pe_data->ns_pri_mask == 0U)
return NULL;
old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
/*
* When exiting secure world, the current Priority Mask must be
* GIC_HIGHEST_NS_PRIORITY (as set during entry), or the Non-secure
* priority mask set upon calling ehf_allow_ns_preemption()
*/
if ((old_pmr != GIC_HIGHEST_NS_PRIORITY) &&
(old_pmr != pe_data->ns_pri_mask)) {
ERROR("Invalid Priority Mask (0x%x) restored\n", old_pmr);
panic();
}
EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
pe_data->ns_pri_mask = 0;
return NULL;
}
/*
* Program Priority Mask to the original Non-secure priority such that
* Non-secure interrupts may preempt Secure execution (for example, during
* Yielding SMC calls). The 'preempt_ret_code' parameter indicates the Yielding
* SMC's return value in case the call was preempted.
*
* This API is expected to be invoked before delegating a yielding SMC to Secure
* EL1. I.e. within the window of secure execution after Non-secure context is
* saved (after entry into EL3) and Secure context is restored (before entering
* Secure EL1).
*/
void ehf_allow_ns_preemption(uint64_t preempt_ret_code)
{
cpu_context_t *ns_ctx;
unsigned int old_pmr __unused;
pe_exc_data_t *pe_data = this_cpu_data();
/*
* We should have been notified earlier of entering secure world, and
* therefore have stashed the Non-secure priority mask.
*/
assert(pe_data->ns_pri_mask != 0U);
/* Make sure no priority levels are active when requesting this */
if (has_valid_pri_activations(pe_data)) {
ERROR("PE %lx has priority activations: 0x%x\n",
read_mpidr_el1(), pe_data->active_pri_bits);
panic();
}
/*
* Program preempted return code to x0 right away so that, if the
* Yielding SMC was indeed preempted before a dispatcher gets a chance
* to populate it, the caller would find the correct return value.
*/
ns_ctx = cm_get_context(NON_SECURE);
assert(ns_ctx != NULL);
write_ctx_reg(get_gpregs_ctx(ns_ctx), CTX_GPREG_X0, preempt_ret_code);
old_pmr = plat_ic_set_priority_mask(pe_data->ns_pri_mask);
EHF_LOG("Priority Mask: 0x%x => 0x%x\n", old_pmr, pe_data->ns_pri_mask);
pe_data->ns_pri_mask = 0;
}
/*
* Return whether Secure execution has explicitly allowed Non-secure interrupts
* to preempt itself (for example, during Yielding SMC calls).
*/
unsigned int ehf_is_ns_preemption_allowed(void)
{
unsigned int run_pri;
pe_exc_data_t *pe_data = this_cpu_data();
/* If running priority is in secure range, return false */
run_pri = plat_ic_get_running_priority();
if (IS_PRI_SECURE(run_pri))
return 0;
/*
* If Non-secure preemption was permitted by calling
* ehf_allow_ns_preemption() earlier:
*
* - There wouldn't have been priority activations;
* - We would have cleared the stashed the Non-secure Priority Mask.
*/
if (has_valid_pri_activations(pe_data))
return 0;
if (pe_data->ns_pri_mask != 0U)
return 0;
return 1;
}
/*
* Top-level EL3 interrupt handler.
*/
static uint64_t ehf_el3_interrupt_handler(uint32_t id, uint32_t flags,
void *handle, void *cookie)
{
int ret = 0;
uint32_t intr_raw;
unsigned int intr, pri, idx;
ehf_handler_t handler;
/*
* Top-level interrupt type handler from Interrupt Management Framework
* doesn't acknowledge the interrupt; so the interrupt ID must be
* invalid.
*/
assert(id == INTR_ID_UNAVAILABLE);
/*
* Acknowledge interrupt. Proceed with handling only for valid interrupt
* IDs. This situation may arise because of Interrupt Management
* Framework identifying an EL3 interrupt, but before it's been
* acknowledged here, the interrupt was either deasserted, or there was
* a higher-priority interrupt of another type.
*/
intr_raw = plat_ic_acknowledge_interrupt();
intr = plat_ic_get_interrupt_id(intr_raw);
if (intr == INTR_ID_UNAVAILABLE)
return 0;
/* Having acknowledged the interrupt, get the running priority */
pri = plat_ic_get_running_priority();
/* Check EL3 interrupt priority is in secure range */
assert(IS_PRI_SECURE(pri));
/*
* Translate the priority to a descriptor index. We do this by masking
* and shifting the running priority value (platform-supplied).
*/
idx = pri_to_idx(pri);
/* Validate priority */
assert(pri == IDX_TO_PRI(idx));
handler = (ehf_handler_t) RAW_HANDLER(
exception_data.ehf_priorities[idx].ehf_handler);
if (handler == NULL) {
ERROR("No EL3 exception handler for priority 0x%x\n",
IDX_TO_PRI(idx));
panic();
}
/*
* Call registered handler. Pass the raw interrupt value to registered
* handlers.
*/
ret = handler(intr_raw, flags, handle, cookie);
return (uint64_t) ret;
}
/*
* Initialize the EL3 exception handling.
*/
void __init ehf_init(void)
{
unsigned int flags = 0;
int ret __unused;
/* Ensure EL3 interrupts are supported */
assert(plat_ic_has_interrupt_type(INTR_TYPE_EL3) != 0);
/*
* Make sure that priority water mark has enough bits to represent the
* whole priority array.
*/
assert(exception_data.num_priorities <= (sizeof(ehf_pri_bits_t) * 8U));
assert(exception_data.ehf_priorities != NULL);
/*
* Bit 7 of GIC priority must be 0 for secure interrupts. This means
* platforms must use at least 1 of the remaining 7 bits.
*/
assert((exception_data.pri_bits >= 1U) ||
(exception_data.pri_bits < 8U));
/* Route EL3 interrupts when in Secure and Non-secure. */
set_interrupt_rm_flag(flags, NON_SECURE);
set_interrupt_rm_flag(flags, SECURE);
/* Register handler for EL3 interrupts */
ret = register_interrupt_type_handler(INTR_TYPE_EL3,
ehf_el3_interrupt_handler, flags);
assert(ret == 0);
}
/*
* Register a handler at the supplied priority. Registration is allowed only if
* a handler hasn't been registered before, or one wasn't provided at build
* time. The priority for which the handler is being registered must also accord
* with the platform-supplied data.
*/
void ehf_register_priority_handler(unsigned int pri, ehf_handler_t handler)
{
unsigned int idx;
/* Sanity check for handler */
assert(handler != NULL);
/* Handler ought to be 4-byte aligned */
assert((((uintptr_t) handler) & 3U) == 0U);
/* Ensure we register for valid priority */
idx = pri_to_idx(pri);
assert(idx < exception_data.num_priorities);
assert(IDX_TO_PRI(idx) == pri);
/* Return failure if a handler was already registered */
if (exception_data.ehf_priorities[idx].ehf_handler != EHF_NO_HANDLER_) {
ERROR("Handler already registered for priority 0x%x\n", pri);
panic();
}
/*
* Install handler, and retain the valid bit. We assume that the handler
* is 4-byte aligned, which is usually the case.
*/
exception_data.ehf_priorities[idx].ehf_handler =
(((uintptr_t) handler) | EHF_PRI_VALID_);
EHF_LOG("register pri=0x%x handler=%p\n", pri, handler);
}
SUBSCRIBE_TO_EVENT(cm_entering_normal_world, ehf_entering_normal_world);
SUBSCRIBE_TO_EVENT(cm_exited_normal_world, ehf_exited_normal_world);

View File

@@ -0,0 +1,227 @@
/*
* Copyright (c) 2014-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <common/bl_common.h>
#include <bl31/interrupt_mgmt.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <plat/common/platform.h>
/*******************************************************************************
* Local structure and corresponding array to keep track of the state of the
* registered interrupt handlers for each interrupt type.
* The field descriptions are:
*
* 'scr_el3[2]' : Mapping of the routing model in the 'flags' field to the
* value of the SCR_EL3.IRQ or FIQ bit for each security state.
* There are two instances of this field corresponding to the
* two security states.
*
* 'flags' : Bit[0], Routing model for this interrupt type when execution is
* not in EL3 in the secure state. '1' implies that this
* interrupt will be routed to EL3. '0' implies that this
* interrupt will be routed to the current exception level.
*
* Bit[1], Routing model for this interrupt type when execution is
* not in EL3 in the non-secure state. '1' implies that this
* interrupt will be routed to EL3. '0' implies that this
* interrupt will be routed to the current exception level.
*
* All other bits are reserved and SBZ.
******************************************************************************/
typedef struct intr_type_desc {
interrupt_type_handler_t handler;
u_register_t scr_el3[2];
uint32_t flags;
} intr_type_desc_t;
static intr_type_desc_t intr_type_descs[MAX_INTR_TYPES];
/*******************************************************************************
* This function validates the interrupt type.
******************************************************************************/
static int32_t validate_interrupt_type(uint32_t type)
{
if ((type == INTR_TYPE_S_EL1) || (type == INTR_TYPE_NS) ||
(type == INTR_TYPE_EL3))
return 0;
return -EINVAL;
}
/*******************************************************************************
* This function validates the routing model for this type of interrupt
******************************************************************************/
static int32_t validate_routing_model(uint32_t type, uint32_t flags)
{
uint32_t rm_flags = (flags >> INTR_RM_FLAGS_SHIFT) & INTR_RM_FLAGS_MASK;
if (type == INTR_TYPE_S_EL1)
return validate_sel1_interrupt_rm(rm_flags);
if (type == INTR_TYPE_NS)
return validate_ns_interrupt_rm(rm_flags);
if (type == INTR_TYPE_EL3)
return validate_el3_interrupt_rm(rm_flags);
return -EINVAL;
}
/*******************************************************************************
* This function returns the cached copy of the SCR_EL3 which contains the
* routing model (expressed through the IRQ and FIQ bits) for a security state
* which was stored through a call to 'set_routing_model()' earlier.
******************************************************************************/
u_register_t get_scr_el3_from_routing_model(uint32_t security_state)
{
u_register_t scr_el3;
assert(sec_state_is_valid(security_state));
scr_el3 = intr_type_descs[INTR_TYPE_NS].scr_el3[security_state];
scr_el3 |= intr_type_descs[INTR_TYPE_S_EL1].scr_el3[security_state];
scr_el3 |= intr_type_descs[INTR_TYPE_EL3].scr_el3[security_state];
return scr_el3;
}
/*******************************************************************************
* This function uses the 'interrupt_type_flags' parameter to obtain the value
* of the trap bit (IRQ/FIQ) in the SCR_EL3 for a security state for this
* interrupt type. It uses it to update the SCR_EL3 in the cpu context and the
* 'intr_type_desc' for that security state.
******************************************************************************/
static void set_scr_el3_from_rm(uint32_t type,
uint32_t interrupt_type_flags,
uint32_t security_state)
{
uint32_t flag, bit_pos;
flag = get_interrupt_rm_flag(interrupt_type_flags, security_state);
bit_pos = plat_interrupt_type_to_line(type, security_state);
intr_type_descs[type].scr_el3[security_state] = (u_register_t)flag << bit_pos;
/*
* Update scr_el3 only if there is a context available. If not, it
* will be updated later during context initialization which will obtain
* the scr_el3 value to be used via get_scr_el3_from_routing_model()
*/
if (cm_get_context(security_state) != NULL)
cm_write_scr_el3_bit(security_state, bit_pos, flag);
}
/*******************************************************************************
* This function validates the routing model specified in the 'flags' and
* updates internal data structures to reflect the new routing model. It also
* updates the copy of SCR_EL3 for each security state with the new routing
* model in the 'cpu_context' structure for this cpu.
******************************************************************************/
int32_t set_routing_model(uint32_t type, uint32_t flags)
{
int32_t rc;
rc = validate_interrupt_type(type);
if (rc != 0)
return rc;
rc = validate_routing_model(type, flags);
if (rc != 0)
return rc;
/* Update the routing model in internal data structures */
intr_type_descs[type].flags = flags;
set_scr_el3_from_rm(type, flags, SECURE);
set_scr_el3_from_rm(type, flags, NON_SECURE);
return 0;
}
/******************************************************************************
* This function disables the routing model of interrupt 'type' from the
* specified 'security_state' on the local core. The disable is in effect
* till the core powers down or till the next enable for that interrupt
* type.
*****************************************************************************/
int disable_intr_rm_local(uint32_t type, uint32_t security_state)
{
uint32_t bit_pos, flag;
assert(intr_type_descs[type].handler != NULL);
flag = get_interrupt_rm_flag(INTR_DEFAULT_RM, security_state);
bit_pos = plat_interrupt_type_to_line(type, security_state);
cm_write_scr_el3_bit(security_state, bit_pos, flag);
return 0;
}
/******************************************************************************
* This function enables the routing model of interrupt 'type' from the
* specified 'security_state' on the local core.
*****************************************************************************/
int enable_intr_rm_local(uint32_t type, uint32_t security_state)
{
uint32_t bit_pos, flag;
assert(intr_type_descs[type].handler != NULL);
flag = get_interrupt_rm_flag(intr_type_descs[type].flags,
security_state);
bit_pos = plat_interrupt_type_to_line(type, security_state);
cm_write_scr_el3_bit(security_state, bit_pos, flag);
return 0;
}
/*******************************************************************************
* This function registers a handler for the 'type' of interrupt specified. It
* also validates the routing model specified in the 'flags' for this type of
* interrupt.
******************************************************************************/
int32_t register_interrupt_type_handler(uint32_t type,
interrupt_type_handler_t handler,
uint32_t flags)
{
int32_t rc;
/* Validate the 'handler' parameter */
if (handler == NULL)
return -EINVAL;
/* Validate the 'flags' parameter */
if ((flags & INTR_TYPE_FLAGS_MASK) != 0U)
return -EINVAL;
/* Check if a handler has already been registered */
if (intr_type_descs[type].handler != NULL)
return -EALREADY;
rc = set_routing_model(type, flags);
if (rc != 0)
return rc;
/* Save the handler */
intr_type_descs[type].handler = handler;
return 0;
}
/*******************************************************************************
* This function is called when an interrupt is generated and returns the
* handler for the interrupt type (if registered). It returns NULL if the
* interrupt type is not supported or its handler has not been registered.
******************************************************************************/
interrupt_type_handler_t get_interrupt_type_handler(uint32_t type)
{
if (validate_interrupt_type(type) != 0)
return NULL;
return intr_type_descs[type].handler;
}

View File

@@ -0,0 +1,15 @@
#
# Copyright (c) 2016-2019, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# This makefile only aims at complying with Trusted Firmware-A build process so
# that "optee" is a valid TF-A AArch32 Secure Playload identifier.
ifneq ($(ARCH),aarch32)
$(error This directory targets AArch32 support)
endif
$(eval $(call add_define,AARCH32_SP_OPTEE))
$(info Trusted Firmware-A built for OP-TEE payload support)

View File

@@ -0,0 +1,382 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <common/runtime_svc.h>
#include <context.h>
#include <el3_common_macros.S>
#include <lib/el3_runtime/cpu_data.h>
#include <lib/pmf/aarch32/pmf_asm_macros.S>
#include <lib/runtime_instr.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#include <smccc_helpers.h>
#include <smccc_macros.S>
.globl sp_min_vector_table
.globl sp_min_entrypoint
.globl sp_min_warm_entrypoint
.globl sp_min_handle_smc
.globl sp_min_handle_fiq
#define FIXUP_SIZE ((BL32_LIMIT) - (BL32_BASE))
.macro route_fiq_to_sp_min reg
/* -----------------------------------------------------
* FIQs are secure interrupts trapped by Monitor and non
* secure is not allowed to mask the FIQs.
* -----------------------------------------------------
*/
ldcopr \reg, SCR
orr \reg, \reg, #SCR_FIQ_BIT
bic \reg, \reg, #SCR_FW_BIT
stcopr \reg, SCR
.endm
.macro clrex_on_monitor_entry
#if (ARM_ARCH_MAJOR == 7)
/*
* ARMv7 architectures need to clear the exclusive access when
* entering Monitor mode.
*/
clrex
#endif
.endm
vector_base sp_min_vector_table
b sp_min_entrypoint
b plat_panic_handler /* Undef */
b sp_min_handle_smc /* Syscall */
b plat_panic_handler /* Prefetch abort */
b plat_panic_handler /* Data abort */
b plat_panic_handler /* Reserved */
b plat_panic_handler /* IRQ */
b sp_min_handle_fiq /* FIQ */
/*
* The Cold boot/Reset entrypoint for SP_MIN
*/
func sp_min_entrypoint
#if !RESET_TO_SP_MIN
/* ---------------------------------------------------------------
* Preceding bootloader has populated r0 with a pointer to a
* 'bl_params_t' structure & r1 with a pointer to platform
* specific structure
* ---------------------------------------------------------------
*/
mov r9, r0
mov r10, r1
mov r11, r2
mov r12, r3
/* ---------------------------------------------------------------------
* For !RESET_TO_SP_MIN systems, only the primary CPU ever reaches
* sp_min_entrypoint() during the cold boot flow, so the cold/warm boot
* and primary/secondary CPU logic should not be executed in this case.
*
* Also, assume that the previous bootloader has already initialised the
* SCTLR, including the CPU endianness, and has initialised the memory.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=0 \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=1 \
_exception_vectors=sp_min_vector_table \
_pie_fixup_size=FIXUP_SIZE
/* ---------------------------------------------------------------------
* Relay the previous bootloader's arguments to the platform layer
* ---------------------------------------------------------------------
*/
#else
/* ---------------------------------------------------------------------
* For RESET_TO_SP_MIN systems which have a programmable reset address,
* sp_min_entrypoint() is executed only on the cold boot path so we can
* skip the warm boot mailbox mechanism.
* ---------------------------------------------------------------------
*/
el3_entrypoint_common \
_init_sctlr=1 \
_warm_boot_mailbox=!PROGRAMMABLE_RESET_ADDRESS \
_secondary_cold_boot=!COLD_BOOT_SINGLE_CPU \
_init_memory=1 \
_init_c_runtime=1 \
_exception_vectors=sp_min_vector_table \
_pie_fixup_size=FIXUP_SIZE
/* ---------------------------------------------------------------------
* For RESET_TO_SP_MIN systems, BL32 (SP_MIN) is the first bootloader
* to run so there's no argument to relay from a previous bootloader.
* Zero the arguments passed to the platform layer to reflect that.
* ---------------------------------------------------------------------
*/
mov r9, #0
mov r10, #0
mov r11, #0
mov r12, #0
#endif /* RESET_TO_SP_MIN */
#if SP_MIN_WITH_SECURE_FIQ
route_fiq_to_sp_min r4
#endif
mov r0, r9
mov r1, r10
mov r2, r11
mov r3, r12
bl sp_min_early_platform_setup2
bl sp_min_plat_arch_setup
/* Jump to the main function */
bl sp_min_main
/* -------------------------------------------------------------
* Clean the .data & .bss sections to main memory. This ensures
* that any global data which was initialised by the primary CPU
* is visible to secondary CPUs before they enable their data
* caches and participate in coherency.
* -------------------------------------------------------------
*/
ldr r0, =__DATA_START__
ldr r1, =__DATA_END__
sub r1, r1, r0
bl clean_dcache_range
ldr r0, =__BSS_START__
ldr r1, =__BSS_END__
sub r1, r1, r0
bl clean_dcache_range
bl smc_get_next_ctx
/* r0 points to `smc_ctx_t` */
/* The PSCI cpu_context registers have been copied to `smc_ctx_t` */
b sp_min_exit
endfunc sp_min_entrypoint
/*
* SMC handling function for SP_MIN.
*/
func sp_min_handle_smc
/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
str lr, [sp, #SMC_CTX_LR_MON]
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* Read the timestamp value and store it on top of the C runtime stack.
* The value will be saved to the per-cpu data once the C stack is
* available, as a valid stack is needed to call _cpu_data()
*/
strd r0, r1, [sp, #SMC_CTX_GPREG_R0]
ldcopr16 r0, r1, CNTPCT_64
ldr lr, [sp, #SMC_CTX_SP_MON]
strd r0, r1, [lr, #-8]!
str lr, [sp, #SMC_CTX_SP_MON]
ldrd r0, r1, [sp, #SMC_CTX_GPREG_R0]
#endif
smccc_save_gp_mode_regs
clrex_on_monitor_entry
/*
* `sp` still points to `smc_ctx_t`. Save it to a register
* and restore the C runtime stack pointer to `sp`.
*/
mov r2, sp /* handle */
ldr sp, [r2, #SMC_CTX_SP_MON]
#if ENABLE_RUNTIME_INSTRUMENTATION
/* Save handle to a callee saved register */
mov r6, r2
/*
* Restore the timestamp value and store it in per-cpu data. The value
* will be extracted from per-cpu data by the C level SMC handler and
* saved to the PMF timestamp region.
*/
ldrd r4, r5, [sp], #8
bl _cpu_data
strd r4, r5, [r0, #CPU_DATA_PMF_TS0_OFFSET]
/* Restore handle */
mov r2, r6
#endif
ldr r0, [r2, #SMC_CTX_SCR]
and r3, r0, #SCR_NS_BIT /* flags */
/* Switch to Secure Mode*/
bic r0, #SCR_NS_BIT
stcopr r0, SCR
isb
ldr r0, [r2, #SMC_CTX_GPREG_R0] /* smc_fid */
/* Check whether an SMC64 is issued */
tst r0, #(FUNCID_CC_MASK << FUNCID_CC_SHIFT)
beq 1f
/* SMC32 is not detected. Return error back to caller */
mov r0, #SMC_UNK
str r0, [r2, #SMC_CTX_GPREG_R0]
mov r0, r2
b sp_min_exit
1:
/* SMC32 is detected */
mov r1, #0 /* cookie */
bl handle_runtime_svc
/* `r0` points to `smc_ctx_t` */
b sp_min_exit
endfunc sp_min_handle_smc
/*
* Secure Interrupts handling function for SP_MIN.
*/
func sp_min_handle_fiq
#if !SP_MIN_WITH_SECURE_FIQ
b plat_panic_handler
#else
/* FIQ has a +4 offset for lr compared to preferred return address */
sub lr, lr, #4
/* On SMC entry, `sp` points to `smc_ctx_t`. Save `lr`. */
str lr, [sp, #SMC_CTX_LR_MON]
smccc_save_gp_mode_regs
clrex_on_monitor_entry
/* load run-time stack */
mov r2, sp
ldr sp, [r2, #SMC_CTX_SP_MON]
/* Switch to Secure Mode */
ldr r0, [r2, #SMC_CTX_SCR]
bic r0, #SCR_NS_BIT
stcopr r0, SCR
isb
push {r2, r3}
bl sp_min_fiq
pop {r0, r3}
b sp_min_exit
#endif
endfunc sp_min_handle_fiq
/*
* The Warm boot entrypoint for SP_MIN.
*/
func sp_min_warm_entrypoint
#if ENABLE_RUNTIME_INSTRUMENTATION
/*
* This timestamp update happens with cache off. The next
* timestamp collection will need to do cache maintenance prior
* to timestamp update.
*/
pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_HW_LOW_PWR
ldcopr16 r2, r3, CNTPCT_64
strd r2, r3, [r0]
#endif
/*
* On the warm boot path, most of the EL3 initialisations performed by
* 'el3_entrypoint_common' must be skipped:
*
* - Only when the platform bypasses the BL1/BL32 (SP_MIN) entrypoint by
* programming the reset address do we need to initialied the SCTLR.
* In other cases, we assume this has been taken care by the
* entrypoint code.
*
* - No need to determine the type of boot, we know it is a warm boot.
*
* - Do not try to distinguish between primary and secondary CPUs, this
* notion only exists for a cold boot.
*
* - No need to initialise the memory or the C runtime environment,
* it has been done once and for all on the cold boot path.
*/
el3_entrypoint_common \
_init_sctlr=PROGRAMMABLE_RESET_ADDRESS \
_warm_boot_mailbox=0 \
_secondary_cold_boot=0 \
_init_memory=0 \
_init_c_runtime=0 \
_exception_vectors=sp_min_vector_table \
_pie_fixup_size=0
/*
* We're about to enable MMU and participate in PSCI state coordination.
*
* The PSCI implementation invokes platform routines that enable CPUs to
* participate in coherency. On a system where CPUs are not
* cache-coherent without appropriate platform specific programming,
* having caches enabled until such time might lead to coherency issues
* (resulting from stale data getting speculatively fetched, among
* others). Therefore we keep data caches disabled even after enabling
* the MMU for such platforms.
*
* On systems with hardware-assisted coherency, or on single cluster
* platforms, such platform specific programming is not required to
* enter coherency (as CPUs already are); and there's no reason to have
* caches disabled either.
*/
#if HW_ASSISTED_COHERENCY || WARMBOOT_ENABLE_DCACHE_EARLY
mov r0, #0
#else
mov r0, #DISABLE_DCACHE
#endif
bl bl32_plat_enable_mmu
#if SP_MIN_WITH_SECURE_FIQ
route_fiq_to_sp_min r0
#endif
bl sp_min_warm_boot
bl smc_get_next_ctx
/* r0 points to `smc_ctx_t` */
/* The PSCI cpu_context registers have been copied to `smc_ctx_t` */
#if ENABLE_RUNTIME_INSTRUMENTATION
/* Save smc_ctx_t */
mov r5, r0
pmf_calc_timestamp_addr rt_instr_svc, RT_INSTR_EXIT_PSCI
mov r4, r0
/*
* Invalidate before updating timestamp to ensure previous timestamp
* updates on the same cache line with caches disabled are properly
* seen by the same core. Without the cache invalidate, the core might
* write into a stale cache line.
*/
mov r1, #PMF_TS_SIZE
bl inv_dcache_range
ldcopr16 r0, r1, CNTPCT_64
strd r0, r1, [r4]
/* Restore smc_ctx_t */
mov r0, r5
#endif
b sp_min_exit
endfunc sp_min_warm_entrypoint
/*
* The function to restore the registers from SMC context and return
* to the mode restored to SPSR.
*
* Arguments : r0 must point to the SMC context to restore from.
*/
func sp_min_exit
monitor_exit
endfunc sp_min_exit

View File

@@ -0,0 +1,150 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
ENTRY(sp_min_vector_table)
MEMORY {
RAM (rwx): ORIGIN = BL32_BASE, LENGTH = BL32_LIMIT - BL32_BASE
}
#ifdef PLAT_SP_MIN_EXTRA_LD_SCRIPT
#include <plat_sp_min.ld.S>
#endif
SECTIONS
{
. = BL32_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL32_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
*entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
/* .ARM.extab and .ARM.exidx are only added because Clang need them */
.ARM.extab . : {
*(.ARM.extab* .gnu.linkonce.armextab.*)
} >RAM
.ARM.exidx . : {
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
/* Place pubsub sections for events */
. = ALIGN(8);
#include <lib/el3_runtime/pubsub_events.h>
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
ro . : {
__RO_START__ = .;
*entrypoint.o(.text*)
*(SORT_BY_ALIGNMENT(.text*))
*(SORT_BY_ALIGNMENT(.rodata*))
RODATA_COMMON
/* Place pubsub sections for events */
. = ALIGN(8);
#include <lib/el3_runtime/pubsub_events.h>
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
ASSERT(__CPU_OPS_END__ > __CPU_OPS_START__,
"cpu_ops not defined for this platform.")
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
RELA_SECTION >RAM
#ifdef BL32_PROGBITS_LIMIT
ASSERT(. <= BL32_PROGBITS_LIMIT, "BL32 progbits has exceeded its limit.")
#endif
STACK_SECTION >RAM
BSS_SECTION >RAM
XLAT_TABLE_SECTION >RAM
__BSS_SIZE__ = SIZEOF(.bss);
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
/*
* Bakery locks are stored in coherent memory
*
* Each lock's data is contiguous and fully allocated by the compiler
*/
*(bakery_lock)
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
__COHERENT_RAM_UNALIGNED_SIZE__ =
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif
/*
* Define a linker symbol to mark the end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL32_END__ = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
}
ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
}

View File

@@ -0,0 +1,77 @@
#
# Copyright (c) 2016-2022, Arm Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
ifneq (${ARCH}, aarch32)
$(error SP_MIN is only supported on AArch32 platforms)
endif
include lib/extensions/amu/amu.mk
include lib/psci/psci_lib.mk
INCLUDES += -Iinclude/bl32/sp_min
BL32_SOURCES += bl32/sp_min/sp_min_main.c \
bl32/sp_min/aarch32/entrypoint.S \
common/runtime_svc.c \
plat/common/aarch32/plat_sp_min_common.c\
services/std_svc/std_svc_setup.c \
${PSCI_LIB_SOURCES}
ifeq (${DISABLE_MTPMU},1)
BL32_SOURCES += lib/extensions/mtpmu/aarch32/mtpmu.S
endif
ifeq (${ENABLE_PMF}, 1)
BL32_SOURCES += lib/pmf/pmf_main.c
endif
ifeq (${ENABLE_AMU},1)
BL32_SOURCES += ${AMU_SOURCES}
endif
ifeq (${WORKAROUND_CVE_2017_5715},1)
BL32_SOURCES += bl32/sp_min/wa_cve_2017_5715_bpiall.S \
bl32/sp_min/wa_cve_2017_5715_icache_inv.S
else
ifeq (${WORKAROUND_CVE_2022_23960},1)
BL32_SOURCES += bl32/sp_min/wa_cve_2017_5715_icache_inv.S
endif
endif
ifeq (${TRNG_SUPPORT},1)
BL32_SOURCES += services/std_svc/trng/trng_main.c \
services/std_svc/trng/trng_entropy_pool.c
endif
ifeq (${ENABLE_SYS_REG_TRACE_FOR_NS},1)
BL32_SOURCES += lib/extensions/sys_reg_trace/aarch32/sys_reg_trace.c
endif
ifeq (${ENABLE_TRF_FOR_NS},1)
BL32_SOURCES += lib/extensions/trf/aarch32/trf.c
endif
BL32_LINKERFILE := bl32/sp_min/sp_min.ld.S
# Include the platform-specific SP_MIN Makefile
# If no platform-specific SP_MIN Makefile exists, it means SP_MIN is not supported
# on this platform.
SP_MIN_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/sp_min/sp_min-${PLAT}.mk)
ifeq (,${SP_MIN_PLAT_MAKEFILE})
$(error SP_MIN is not supported on platform ${PLAT})
else
include ${SP_MIN_PLAT_MAKEFILE}
endif
RESET_TO_SP_MIN := 0
$(eval $(call add_define,RESET_TO_SP_MIN))
$(eval $(call assert_boolean,RESET_TO_SP_MIN))
# Flag to allow SP_MIN to handle FIQ interrupts in monitor mode. The platform
# port is free to override this value. It is default disabled.
SP_MIN_WITH_SECURE_FIQ ?= 0
$(eval $(call add_define,SP_MIN_WITH_SECURE_FIQ))
$(eval $(call assert_boolean,SP_MIN_WITH_SECURE_FIQ))

View File

@@ -0,0 +1,249 @@
/*
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include <platform_def.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <context.h>
#include <drivers/console.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/pmf/pmf.h>
#include <lib/psci/psci.h>
#include <lib/runtime_instr.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <platform_sp_min.h>
#include <services/std_svc.h>
#include <smccc_helpers.h>
#include "sp_min_private.h"
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_REGISTER_SERVICE_SMC(rt_instr_svc, PMF_RT_INSTR_SVC_ID,
RT_INSTR_TOTAL_IDS, PMF_STORE_ENABLE)
#endif
/* Pointers to per-core cpu contexts */
static void *sp_min_cpu_ctx_ptr[PLATFORM_CORE_COUNT];
/* SP_MIN only stores the non secure smc context */
static smc_ctx_t sp_min_smc_context[PLATFORM_CORE_COUNT];
/******************************************************************************
* Define the smccc helper library APIs
*****************************************************************************/
void *smc_get_ctx(unsigned int security_state)
{
assert(security_state == NON_SECURE);
return &sp_min_smc_context[plat_my_core_pos()];
}
void smc_set_next_ctx(unsigned int security_state)
{
assert(security_state == NON_SECURE);
/* SP_MIN stores only non secure smc context. Nothing to do here */
}
void *smc_get_next_ctx(void)
{
return &sp_min_smc_context[plat_my_core_pos()];
}
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the calling CPU that was set as the context for the specified security
* state. NULL is returned if no such structure has been specified.
******************************************************************************/
void *cm_get_context(uint32_t security_state)
{
assert(security_state == NON_SECURE);
return sp_min_cpu_ctx_ptr[plat_my_core_pos()];
}
/*******************************************************************************
* This function sets the pointer to the current 'cpu_context' structure for the
* specified security state for the calling CPU
******************************************************************************/
void cm_set_context(void *context, uint32_t security_state)
{
assert(security_state == NON_SECURE);
sp_min_cpu_ctx_ptr[plat_my_core_pos()] = context;
}
/*******************************************************************************
* This function returns a pointer to the most recent 'cpu_context' structure
* for the CPU identified by `cpu_idx` that was set as the context for the
* specified security state. NULL is returned if no such structure has been
* specified.
******************************************************************************/
void *cm_get_context_by_index(unsigned int cpu_idx,
unsigned int security_state)
{
assert(security_state == NON_SECURE);
return sp_min_cpu_ctx_ptr[cpu_idx];
}
/*******************************************************************************
* This function sets the pointer to the current 'cpu_context' structure for the
* specified security state for the CPU identified by CPU index.
******************************************************************************/
void cm_set_context_by_index(unsigned int cpu_idx, void *context,
unsigned int security_state)
{
assert(security_state == NON_SECURE);
sp_min_cpu_ctx_ptr[cpu_idx] = context;
}
static void copy_cpu_ctx_to_smc_stx(const regs_t *cpu_reg_ctx,
smc_ctx_t *next_smc_ctx)
{
next_smc_ctx->r0 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R0);
next_smc_ctx->r1 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R1);
next_smc_ctx->r2 = read_ctx_reg(cpu_reg_ctx, CTX_GPREG_R2);
next_smc_ctx->lr_mon = read_ctx_reg(cpu_reg_ctx, CTX_LR);
next_smc_ctx->spsr_mon = read_ctx_reg(cpu_reg_ctx, CTX_SPSR);
next_smc_ctx->scr = read_ctx_reg(cpu_reg_ctx, CTX_SCR);
}
/*******************************************************************************
* This function invokes the PSCI library interface to initialize the
* non secure cpu context and copies the relevant cpu context register values
* to smc context. These registers will get programmed during `smc_exit`.
******************************************************************************/
static void sp_min_prepare_next_image_entry(void)
{
entry_point_info_t *next_image_info;
cpu_context_t *ctx = cm_get_context(NON_SECURE);
u_register_t ns_sctlr;
/* Program system registers to proceed to non-secure */
next_image_info = sp_min_plat_get_bl33_ep_info();
assert(next_image_info);
assert(NON_SECURE == GET_SECURITY_STATE(next_image_info->h.attr));
INFO("SP_MIN: Preparing exit to normal world\n");
psci_prepare_next_non_secure_ctx(next_image_info);
smc_set_next_ctx(NON_SECURE);
/* Copy r0, lr and spsr from cpu context to SMC context */
copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
smc_get_next_ctx());
/* Temporarily set the NS bit to access NS SCTLR */
write_scr(read_scr() | SCR_NS_BIT);
isb();
ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
write_sctlr(ns_sctlr);
isb();
write_scr(read_scr() & ~SCR_NS_BIT);
isb();
}
/******************************************************************************
* Implement the ARM Standard Service function to get arguments for a
* particular service.
*****************************************************************************/
uintptr_t get_arm_std_svc_args(unsigned int svc_mask)
{
/* Setup the arguments for PSCI Library */
DEFINE_STATIC_PSCI_LIB_ARGS_V1(psci_args, sp_min_warm_entrypoint);
/* PSCI is the only ARM Standard Service implemented */
assert(svc_mask == PSCI_FID_MASK);
return (uintptr_t)&psci_args;
}
/******************************************************************************
* The SP_MIN main function. Do the platform and PSCI Library setup. Also
* initialize the runtime service framework.
*****************************************************************************/
void sp_min_main(void)
{
NOTICE("SP_MIN: %s\n", version_string);
NOTICE("SP_MIN: %s\n", build_message);
/* Perform the SP_MIN platform setup */
sp_min_platform_setup();
/* Initialize the runtime services e.g. psci */
INFO("SP_MIN: Initializing runtime services\n");
runtime_svc_init();
/*
* We are ready to enter the next EL. Prepare entry into the image
* corresponding to the desired security state after the next ERET.
*/
sp_min_prepare_next_image_entry();
/*
* Perform any platform specific runtime setup prior to cold boot exit
* from SP_MIN.
*/
sp_min_plat_runtime_setup();
console_flush();
}
/******************************************************************************
* This function is invoked during warm boot. Invoke the PSCI library
* warm boot entry point which takes care of Architectural and platform setup/
* restore. Copy the relevant cpu_context register values to smc context which
* will get programmed during `smc_exit`.
*****************************************************************************/
void sp_min_warm_boot(void)
{
smc_ctx_t *next_smc_ctx;
cpu_context_t *ctx = cm_get_context(NON_SECURE);
u_register_t ns_sctlr;
psci_warmboot_entrypoint();
smc_set_next_ctx(NON_SECURE);
next_smc_ctx = smc_get_next_ctx();
zeromem(next_smc_ctx, sizeof(smc_ctx_t));
copy_cpu_ctx_to_smc_stx(get_regs_ctx(cm_get_context(NON_SECURE)),
next_smc_ctx);
/* Temporarily set the NS bit to access NS SCTLR */
write_scr(read_scr() | SCR_NS_BIT);
isb();
ns_sctlr = read_ctx_reg(get_regs_ctx(ctx), CTX_NS_SCTLR);
write_sctlr(ns_sctlr);
isb();
write_scr(read_scr() & ~SCR_NS_BIT);
isb();
}
#if SP_MIN_WITH_SECURE_FIQ
/******************************************************************************
* This function is invoked on secure interrupts. By construction of the
* SP_MIN, secure interrupts can only be handled when core executes in non
* secure state.
*****************************************************************************/
void sp_min_fiq(void)
{
uint32_t id;
id = plat_ic_acknowledge_interrupt();
sp_min_plat_fiq_handler(id);
plat_ic_end_of_interrupt(id);
}
#endif /* SP_MIN_WITH_SECURE_FIQ */

View File

@@ -0,0 +1,14 @@
/*
* Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SP_MIN_PRIVATE_H
#define SP_MIN_PRIVATE_H
void sp_min_main(void);
void sp_min_warm_boot(void);
void sp_min_fiq(void);
#endif /* SP_MIN_PRIVATE_H */

View File

@@ -0,0 +1,74 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
.globl wa_cve_2017_5715_bpiall_vbar
vector_base wa_cve_2017_5715_bpiall_vbar
/* We encode the exception entry in the bottom 3 bits of SP */
add sp, sp, #1 /* Reset: 0b111 */
add sp, sp, #1 /* Undef: 0b110 */
add sp, sp, #1 /* Syscall: 0b101 */
add sp, sp, #1 /* Prefetch abort: 0b100 */
add sp, sp, #1 /* Data abort: 0b011 */
add sp, sp, #1 /* Reserved: 0b010 */
add sp, sp, #1 /* IRQ: 0b001 */
nop /* FIQ: 0b000 */
/*
* Invalidate the branch predictor, `r0` is a dummy register
* and is unused.
*/
stcopr r0, BPIALL
isb
/*
* As we cannot use any temporary registers and cannot
* clobber SP, we can decode the exception entry using
* an unrolled binary search.
*
* Note, if this code is re-used by other secure payloads,
* the below exception entry vectors must be changed to
* the vectors specific to that secure payload.
*/
tst sp, #4
bne 1f
tst sp, #2
bne 3f
/* Expected encoding: 0x1 and 0x0 */
tst sp, #1
/* Restore original value of SP by clearing the bottom 3 bits */
bic sp, sp, #0x7
bne plat_panic_handler /* IRQ */
b sp_min_handle_fiq /* FIQ */
1:
tst sp, #2
bne 2f
/* Expected encoding: 0x4 and 0x5 */
tst sp, #1
bic sp, sp, #0x7
bne sp_min_handle_smc /* Syscall */
b plat_panic_handler /* Prefetch abort */
2:
/* Expected encoding: 0x7 and 0x6 */
tst sp, #1
bic sp, sp, #0x7
bne sp_min_entrypoint /* Reset */
b plat_panic_handler /* Undef */
3:
/* Expected encoding: 0x2 and 0x3 */
tst sp, #1
bic sp, sp, #0x7
bne plat_panic_handler /* Data abort */
b plat_panic_handler /* Reserved */

View File

@@ -0,0 +1,75 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
.globl wa_cve_2017_5715_icache_inv_vbar
vector_base wa_cve_2017_5715_icache_inv_vbar
/* We encode the exception entry in the bottom 3 bits of SP */
add sp, sp, #1 /* Reset: 0b111 */
add sp, sp, #1 /* Undef: 0b110 */
add sp, sp, #1 /* Syscall: 0b101 */
add sp, sp, #1 /* Prefetch abort: 0b100 */
add sp, sp, #1 /* Data abort: 0b011 */
add sp, sp, #1 /* Reserved: 0b010 */
add sp, sp, #1 /* IRQ: 0b001 */
nop /* FIQ: 0b000 */
/*
* Invalidate the instruction cache, which we assume also
* invalidates the branch predictor. This may depend on
* other CPU specific changes (e.g. an ACTLR setting).
*/
stcopr r0, ICIALLU
isb
/*
* As we cannot use any temporary registers and cannot
* clobber SP, we can decode the exception entry using
* an unrolled binary search.
*
* Note, if this code is re-used by other secure payloads,
* the below exception entry vectors must be changed to
* the vectors specific to that secure payload.
*/
tst sp, #4
bne 1f
tst sp, #2
bne 3f
/* Expected encoding: 0x1 and 0x0 */
tst sp, #1
/* Restore original value of SP by clearing the bottom 3 bits */
bic sp, sp, #0x7
bne plat_panic_handler /* IRQ */
b sp_min_handle_fiq /* FIQ */
1:
/* Expected encoding: 0x4 and 0x5 */
tst sp, #2
bne 2f
tst sp, #1
bic sp, sp, #0x7
bne sp_min_handle_smc /* Syscall */
b plat_panic_handler /* Prefetch abort */
2:
/* Expected encoding: 0x7 and 0x6 */
tst sp, #1
bic sp, sp, #0x7
bne sp_min_entrypoint /* Reset */
b plat_panic_handler /* Undef */
3:
/* Expected encoding: 0x2 and 0x3 */
tst sp, #1
bic sp, sp, #0x7
bne plat_panic_handler /* Data abort */
b plat_panic_handler /* Reserved */

View File

@@ -0,0 +1,485 @@
/*
* Copyright (c) 2013-2021, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#include <arch.h>
#include <asm_macros.S>
#include <bl32/tsp/tsp.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
#include "../tsp_private.h"
.globl tsp_entrypoint
.globl tsp_vector_table
/* ---------------------------------------------
* Populate the params in x0-x7 from the pointer
* to the smc args structure in x0.
* ---------------------------------------------
*/
.macro restore_args_call_smc
ldp x6, x7, [x0, #TSP_ARG6]
ldp x4, x5, [x0, #TSP_ARG4]
ldp x2, x3, [x0, #TSP_ARG2]
ldp x0, x1, [x0, #TSP_ARG0]
smc #0
.endm
.macro save_eret_context reg1 reg2
mrs \reg1, elr_el1
mrs \reg2, spsr_el1
stp \reg1, \reg2, [sp, #-0x10]!
stp x30, x18, [sp, #-0x10]!
.endm
.macro restore_eret_context reg1 reg2
ldp x30, x18, [sp], #0x10
ldp \reg1, \reg2, [sp], #0x10
msr elr_el1, \reg1
msr spsr_el1, \reg2
.endm
func tsp_entrypoint _align=3
#if ENABLE_PIE
/*
* ------------------------------------------------------------
* If PIE is enabled fixup the Global descriptor Table only
* once during primary core cold boot path.
*
* Compile time base address, required for fixup, is calculated
* using "pie_fixup" label present within first page.
* ------------------------------------------------------------
*/
pie_fixup:
ldr x0, =pie_fixup
and x0, x0, #~(PAGE_SIZE_MASK)
mov_imm x1, (BL32_LIMIT - BL32_BASE)
add x1, x1, x0
bl fixup_gdt_reloc
#endif /* ENABLE_PIE */
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
adr x0, tsp_exceptions
msr vbar_el1, x0
isb
/* ---------------------------------------------
* Enable the SError interrupt now that the
* exception vectors have been setup.
* ---------------------------------------------
*/
msr daifclr, #DAIF_ABT_BIT
/* ---------------------------------------------
* Enable the instruction cache, stack pointer
* and data access alignment checks and disable
* speculative loads.
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
bic x0, x0, #SCTLR_DSSBS_BIT
msr sctlr_el1, x0
isb
/* ---------------------------------------------
* Invalidate the RW memory used by the BL32
* image. This includes the data and NOBITS
* sections. This is done to safeguard against
* possible corruption of this memory by dirty
* cache lines in a system cache as a result of
* use by an earlier boot loader stage. If PIE
* is enabled however, RO sections including the
* GOT may be modified during pie fixup.
* Therefore, to be on the safe side, invalidate
* the entire image region if PIE is enabled.
* ---------------------------------------------
*/
#if ENABLE_PIE
#if SEPARATE_CODE_AND_RODATA
adrp x0, __TEXT_START__
add x0, x0, :lo12:__TEXT_START__
#else
adrp x0, __RO_START__
add x0, x0, :lo12:__RO_START__
#endif /* SEPARATE_CODE_AND_RODATA */
#else
adrp x0, __RW_START__
add x0, x0, :lo12:__RW_START__
#endif /* ENABLE_PIE */
adrp x1, __RW_END__
add x1, x1, :lo12:__RW_END__
sub x1, x1, x0
bl inv_dcache_range
/* ---------------------------------------------
* Zero out NOBITS sections. There are 2 of them:
* - the .bss section;
* - the coherent memory section.
* ---------------------------------------------
*/
adrp x0, __BSS_START__
add x0, x0, :lo12:__BSS_START__
adrp x1, __BSS_END__
add x1, x1, :lo12:__BSS_END__
sub x1, x1, x0
bl zeromem
#if USE_COHERENT_MEM
adrp x0, __COHERENT_RAM_START__
add x0, x0, :lo12:__COHERENT_RAM_START__
adrp x1, __COHERENT_RAM_END_UNALIGNED__
add x1, x1, :lo12:__COHERENT_RAM_END_UNALIGNED__
sub x1, x1, x0
bl zeromem
#endif
/* --------------------------------------------
* Allocate a stack whose memory will be marked
* as Normal-IS-WBWA when the MMU is enabled.
* There is no risk of reading stale stack
* memory after enabling the MMU as only the
* primary cpu is running at the moment.
* --------------------------------------------
*/
bl plat_set_my_stack
/* ---------------------------------------------
* Initialize the stack protector canary before
* any C code is called.
* ---------------------------------------------
*/
#if STACK_PROTECTOR_ENABLED
bl update_stack_protector_canary
#endif
/* ---------------------------------------------
* Perform TSP setup
* ---------------------------------------------
*/
bl tsp_setup
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1
* and enable pointer authentication
* ---------------------------------------------
*/
bl pauth_init_enable_el1
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Jump to main function.
* ---------------------------------------------
*/
bl tsp_main
/* ---------------------------------------------
* Tell TSPD that we are done initialising
* ---------------------------------------------
*/
mov x1, x0
mov x0, #TSP_ENTRY_DONE
smc #0
tsp_entrypoint_panic:
b tsp_entrypoint_panic
endfunc tsp_entrypoint
/* -------------------------------------------
* Table of entrypoint vectors provided to the
* TSPD for the various entrypoints
* -------------------------------------------
*/
vector_base tsp_vector_table
b tsp_yield_smc_entry
b tsp_fast_smc_entry
b tsp_cpu_on_entry
b tsp_cpu_off_entry
b tsp_cpu_resume_entry
b tsp_cpu_suspend_entry
b tsp_sel1_intr_entry
b tsp_system_off_entry
b tsp_system_reset_entry
b tsp_abort_yield_smc_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when this
* cpu is to be turned off through a CPU_OFF
* psci call to ask the TSP to perform any
* bookeeping necessary. In the current
* implementation, the TSPD expects the TSP to
* re-initialise its state so nothing is done
* here except for acknowledging the request.
* ---------------------------------------------
*/
func tsp_cpu_off_entry
bl tsp_cpu_off_main
restore_args_call_smc
endfunc tsp_cpu_off_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when the
* system is about to be switched off (through
* a SYSTEM_OFF psci call) to ask the TSP to
* perform any necessary bookkeeping.
* ---------------------------------------------
*/
func tsp_system_off_entry
bl tsp_system_off_main
restore_args_call_smc
endfunc tsp_system_off_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when the
* system is about to be reset (through a
* SYSTEM_RESET psci call) to ask the TSP to
* perform any necessary bookkeeping.
* ---------------------------------------------
*/
func tsp_system_reset_entry
bl tsp_system_reset_main
restore_args_call_smc
endfunc tsp_system_reset_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when this
* cpu is turned on using a CPU_ON psci call to
* ask the TSP to initialise itself i.e. setup
* the mmu, stacks etc. Minimal architectural
* state will be initialised by the TSPD when
* this function is entered i.e. Caches and MMU
* will be turned off, the execution state
* will be aarch64 and exceptions masked.
* ---------------------------------------------
*/
func tsp_cpu_on_entry
/* ---------------------------------------------
* Set the exception vector to something sane.
* ---------------------------------------------
*/
adr x0, tsp_exceptions
msr vbar_el1, x0
isb
/* Enable the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
/* ---------------------------------------------
* Enable the instruction cache, stack pointer
* and data access alignment checks
* ---------------------------------------------
*/
mov x1, #(SCTLR_I_BIT | SCTLR_A_BIT | SCTLR_SA_BIT)
mrs x0, sctlr_el1
orr x0, x0, x1
msr sctlr_el1, x0
isb
/* --------------------------------------------
* Give ourselves a stack whose memory will be
* marked as Normal-IS-WBWA when the MMU is
* enabled.
* --------------------------------------------
*/
bl plat_set_my_stack
/* --------------------------------------------
* Enable MMU and D-caches together.
* --------------------------------------------
*/
mov x0, #0
bl bl32_plat_enable_mmu
#if ENABLE_PAUTH
/* ---------------------------------------------
* Program APIAKey_EL1
* and enable pointer authentication
* ---------------------------------------------
*/
bl pauth_init_enable_el1
#endif /* ENABLE_PAUTH */
/* ---------------------------------------------
* Enter C runtime to perform any remaining
* book keeping
* ---------------------------------------------
*/
bl tsp_cpu_on_main
restore_args_call_smc
/* Should never reach here */
tsp_cpu_on_entry_panic:
b tsp_cpu_on_entry_panic
endfunc tsp_cpu_on_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when this
* cpu is to be suspended through a CPU_SUSPEND
* psci call to ask the TSP to perform any
* bookeeping necessary. In the current
* implementation, the TSPD saves and restores
* the EL1 state.
* ---------------------------------------------
*/
func tsp_cpu_suspend_entry
bl tsp_cpu_suspend_main
restore_args_call_smc
endfunc tsp_cpu_suspend_entry
/*-------------------------------------------------
* This entrypoint is used by the TSPD to pass
* control for `synchronously` handling a S-EL1
* Interrupt which was triggered while executing
* in normal world. 'x0' contains a magic number
* which indicates this. TSPD expects control to
* be handed back at the end of interrupt
* processing. This is done through an SMC.
* The handover agreement is:
*
* 1. PSTATE.DAIF are set upon entry. 'x1' has
* the ELR_EL3 from the non-secure state.
* 2. TSP has to preserve the callee saved
* general purpose registers, SP_EL1/EL0 and
* LR.
* 3. TSP has to preserve the system and vfp
* registers (if applicable).
* 4. TSP can use 'x0-x18' to enable its C
* runtime.
* 5. TSP returns to TSPD using an SMC with
* 'x0' = TSP_HANDLED_S_EL1_INTR
* ------------------------------------------------
*/
func tsp_sel1_intr_entry
#if DEBUG
mov_imm x2, TSP_HANDLE_SEL1_INTR_AND_RETURN
cmp x0, x2
b.ne tsp_sel1_int_entry_panic
#endif
/*-------------------------------------------------
* Save any previous context needed to perform
* an exception return from S-EL1 e.g. context
* from a previous Non secure Interrupt.
* Update statistics and handle the S-EL1
* interrupt before returning to the TSPD.
* IRQ/FIQs are not enabled since that will
* complicate the implementation. Execution
* will be transferred back to the normal world
* in any case. The handler can return 0
* if the interrupt was handled or TSP_PREEMPTED
* if the expected interrupt was preempted
* by an interrupt that should be handled in EL3
* e.g. Group 0 interrupt in GICv3. In both
* the cases switch to EL3 using SMC with id
* TSP_HANDLED_S_EL1_INTR. Any other return value
* from the handler will result in panic.
* ------------------------------------------------
*/
save_eret_context x2 x3
bl tsp_update_sync_sel1_intr_stats
bl tsp_common_int_handler
/* Check if the S-EL1 interrupt has been handled */
cbnz x0, tsp_sel1_intr_check_preemption
b tsp_sel1_intr_return
tsp_sel1_intr_check_preemption:
/* Check if the S-EL1 interrupt has been preempted */
mov_imm x1, TSP_PREEMPTED
cmp x0, x1
b.ne tsp_sel1_int_entry_panic
tsp_sel1_intr_return:
mov_imm x0, TSP_HANDLED_S_EL1_INTR
restore_eret_context x2 x3
smc #0
/* Should never reach here */
tsp_sel1_int_entry_panic:
no_ret plat_panic_handler
endfunc tsp_sel1_intr_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD when this
* cpu resumes execution after an earlier
* CPU_SUSPEND psci call to ask the TSP to
* restore its saved context. In the current
* implementation, the TSPD saves and restores
* EL1 state so nothing is done here apart from
* acknowledging the request.
* ---------------------------------------------
*/
func tsp_cpu_resume_entry
bl tsp_cpu_resume_main
restore_args_call_smc
/* Should never reach here */
no_ret plat_panic_handler
endfunc tsp_cpu_resume_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD to ask
* the TSP to service a fast smc request.
* ---------------------------------------------
*/
func tsp_fast_smc_entry
bl tsp_smc_handler
restore_args_call_smc
/* Should never reach here */
no_ret plat_panic_handler
endfunc tsp_fast_smc_entry
/*---------------------------------------------
* This entrypoint is used by the TSPD to ask
* the TSP to service a Yielding SMC request.
* We will enable preemption during execution
* of tsp_smc_handler.
* ---------------------------------------------
*/
func tsp_yield_smc_entry
msr daifclr, #DAIF_FIQ_BIT | DAIF_IRQ_BIT
bl tsp_smc_handler
msr daifset, #DAIF_FIQ_BIT | DAIF_IRQ_BIT
restore_args_call_smc
/* Should never reach here */
no_ret plat_panic_handler
endfunc tsp_yield_smc_entry
/*---------------------------------------------------------------------
* This entrypoint is used by the TSPD to abort a pre-empted Yielding
* SMC. It could be on behalf of non-secure world or because a CPU
* suspend/CPU off request needs to abort the preempted SMC.
* --------------------------------------------------------------------
*/
func tsp_abort_yield_smc_entry
/*
* Exceptions masking is already done by the TSPD when entering this
* hook so there is no need to do it here.
*/
/* Reset the stack used by the pre-empted SMC */
bl plat_set_my_stack
/*
* Allow some cleanup such as releasing locks.
*/
bl tsp_abort_smc_handler
restore_args_call_smc
/* Should never reach here */
bl plat_panic_handler
endfunc tsp_abort_yield_smc_entry

View File

@@ -0,0 +1,162 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <bl32/tsp/tsp.h>
#include <common/bl_common.h>
/* ----------------------------------------------------
* The caller-saved registers x0-x18 and LR are saved
* here.
* ----------------------------------------------------
*/
#define SCRATCH_REG_SIZE #(20 * 8)
.macro save_caller_regs_and_lr
sub sp, sp, SCRATCH_REG_SIZE
stp x0, x1, [sp]
stp x2, x3, [sp, #0x10]
stp x4, x5, [sp, #0x20]
stp x6, x7, [sp, #0x30]
stp x8, x9, [sp, #0x40]
stp x10, x11, [sp, #0x50]
stp x12, x13, [sp, #0x60]
stp x14, x15, [sp, #0x70]
stp x16, x17, [sp, #0x80]
stp x18, x30, [sp, #0x90]
.endm
.macro restore_caller_regs_and_lr
ldp x0, x1, [sp]
ldp x2, x3, [sp, #0x10]
ldp x4, x5, [sp, #0x20]
ldp x6, x7, [sp, #0x30]
ldp x8, x9, [sp, #0x40]
ldp x10, x11, [sp, #0x50]
ldp x12, x13, [sp, #0x60]
ldp x14, x15, [sp, #0x70]
ldp x16, x17, [sp, #0x80]
ldp x18, x30, [sp, #0x90]
add sp, sp, SCRATCH_REG_SIZE
.endm
/* ----------------------------------------------------
* Common TSP interrupt handling routine
* ----------------------------------------------------
*/
.macro handle_tsp_interrupt label
/* Enable the SError interrupt */
msr daifclr, #DAIF_ABT_BIT
save_caller_regs_and_lr
bl tsp_common_int_handler
cbz x0, interrupt_exit_\label
/*
* This interrupt was not targetted to S-EL1 so send it to
* the monitor and wait for execution to resume.
*/
smc #0
interrupt_exit_\label:
restore_caller_regs_and_lr
exception_return
.endm
.globl tsp_exceptions
/* -----------------------------------------------------
* TSP exception handlers.
* -----------------------------------------------------
*/
vector_base tsp_exceptions
/* -----------------------------------------------------
* Current EL with _sp_el0 : 0x0 - 0x200. No exceptions
* are expected and treated as irrecoverable errors.
* -----------------------------------------------------
*/
vector_entry sync_exception_sp_el0
b plat_panic_handler
end_vector_entry sync_exception_sp_el0
vector_entry irq_sp_el0
b plat_panic_handler
end_vector_entry irq_sp_el0
vector_entry fiq_sp_el0
b plat_panic_handler
end_vector_entry fiq_sp_el0
vector_entry serror_sp_el0
b plat_panic_handler
end_vector_entry serror_sp_el0
/* -----------------------------------------------------
* Current EL with SPx: 0x200 - 0x400. Only IRQs/FIQs
* are expected and handled
* -----------------------------------------------------
*/
vector_entry sync_exception_sp_elx
b plat_panic_handler
end_vector_entry sync_exception_sp_elx
vector_entry irq_sp_elx
handle_tsp_interrupt irq_sp_elx
end_vector_entry irq_sp_elx
vector_entry fiq_sp_elx
handle_tsp_interrupt fiq_sp_elx
end_vector_entry fiq_sp_elx
vector_entry serror_sp_elx
b plat_panic_handler
end_vector_entry serror_sp_elx
/* -----------------------------------------------------
* Lower EL using AArch64 : 0x400 - 0x600. No exceptions
* are handled since TSP does not implement a lower EL
* -----------------------------------------------------
*/
vector_entry sync_exception_aarch64
b plat_panic_handler
end_vector_entry sync_exception_aarch64
vector_entry irq_aarch64
b plat_panic_handler
end_vector_entry irq_aarch64
vector_entry fiq_aarch64
b plat_panic_handler
end_vector_entry fiq_aarch64
vector_entry serror_aarch64
b plat_panic_handler
end_vector_entry serror_aarch64
/* -----------------------------------------------------
* Lower EL using AArch32 : 0x600 - 0x800. No exceptions
* handled since the TSP does not implement a lower EL.
* -----------------------------------------------------
*/
vector_entry sync_exception_aarch32
b plat_panic_handler
end_vector_entry sync_exception_aarch32
vector_entry irq_aarch32
b plat_panic_handler
end_vector_entry irq_aarch32
vector_entry fiq_aarch32
b plat_panic_handler
end_vector_entry fiq_aarch32
vector_entry serror_aarch32
b plat_panic_handler
end_vector_entry serror_aarch32

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <bl32/tsp/tsp.h>
.globl tsp_get_magic
/*
* This function raises an SMC to retrieve arguments from secure
* monitor/dispatcher, saves the returned arguments the array received in x0,
* and then returns to the caller
*/
func tsp_get_magic
/* Load arguments */
ldr w0, _tsp_fid_get_magic
/* Raise SMC */
smc #0
/* Return arguments in x1:x0 */
ret
endfunc tsp_get_magic
.align 2
_tsp_fid_get_magic:
.word TSP_GET_ARGS

View File

@@ -0,0 +1,123 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.ld.h>
#include <lib/xlat_tables/xlat_tables_defs.h>
OUTPUT_FORMAT(PLATFORM_LINKER_FORMAT)
OUTPUT_ARCH(PLATFORM_LINKER_ARCH)
ENTRY(tsp_entrypoint)
MEMORY {
RAM (rwx): ORIGIN = TSP_SEC_MEM_BASE, LENGTH = TSP_SEC_MEM_SIZE
}
SECTIONS
{
. = BL32_BASE;
ASSERT(. == ALIGN(PAGE_SIZE),
"BL32_BASE address is not aligned on a page boundary.")
#if SEPARATE_CODE_AND_RODATA
.text . : {
__TEXT_START__ = .;
*tsp_entrypoint.o(.text*)
*(.text*)
*(.vectors)
. = ALIGN(PAGE_SIZE);
__TEXT_END__ = .;
} >RAM
.rodata . : {
__RODATA_START__ = .;
*(.rodata*)
RODATA_COMMON
. = ALIGN(PAGE_SIZE);
__RODATA_END__ = .;
} >RAM
#else
ro . : {
__RO_START__ = .;
*tsp_entrypoint.o(.text*)
*(.text*)
*(.rodata*)
RODATA_COMMON
*(.vectors)
__RO_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked as
* read-only, executable. No RW data from the next section must
* creep in. Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__RO_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark start of the RW memory area for this
* image.
*/
__RW_START__ = . ;
DATA_SECTION >RAM
RELA_SECTION >RAM
#ifdef TSP_PROGBITS_LIMIT
ASSERT(. <= TSP_PROGBITS_LIMIT, "TSP progbits has exceeded its limit.")
#endif
STACK_SECTION >RAM
BSS_SECTION >RAM
XLAT_TABLE_SECTION >RAM
#if USE_COHERENT_MEM
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
coherent_ram (NOLOAD) : ALIGN(PAGE_SIZE) {
__COHERENT_RAM_START__ = .;
*(tzfw_coherent_mem)
__COHERENT_RAM_END_UNALIGNED__ = .;
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
. = ALIGN(PAGE_SIZE);
__COHERENT_RAM_END__ = .;
} >RAM
#endif
/*
* Define a linker symbol to mark the end of the RW memory area for this
* image.
*/
__RW_END__ = .;
__BL32_END__ = .;
/DISCARD/ : {
*(.dynsym .dynstr .hash .gnu.hash)
}
__BSS_SIZE__ = SIZEOF(.bss);
#if USE_COHERENT_MEM
__COHERENT_RAM_UNALIGNED_SIZE__ =
__COHERENT_RAM_END_UNALIGNED__ - __COHERENT_RAM_START__;
#endif
ASSERT(. <= BL32_LIMIT, "BL32 image has exceeded its limit.")
}

View File

@@ -0,0 +1,36 @@
#
# Copyright (c) 2013-2019, ARM Limited and Contributors. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
INCLUDES += -Iinclude/bl32/tsp
BL32_SOURCES += bl32/tsp/tsp_main.c \
bl32/tsp/aarch64/tsp_entrypoint.S \
bl32/tsp/aarch64/tsp_exceptions.S \
bl32/tsp/aarch64/tsp_request.S \
bl32/tsp/tsp_interrupt.c \
bl32/tsp/tsp_timer.c \
common/aarch64/early_exceptions.S \
lib/locks/exclusive/aarch64/spinlock.S
BL32_LINKERFILE := bl32/tsp/tsp.ld.S
# This flag determines if the TSPD initializes BL32 in tspd_init() (synchronous
# method) or configures BL31 to pass control to BL32 instead of BL33
# (asynchronous method).
TSP_INIT_ASYNC := 0
$(eval $(call assert_boolean,TSP_INIT_ASYNC))
$(eval $(call add_define,TSP_INIT_ASYNC))
# Include the platform-specific TSP Makefile
# If no platform-specific TSP Makefile exists, it means TSP is not supported
# on this platform.
TSP_PLAT_MAKEFILE := $(wildcard ${PLAT_DIR}/tsp/tsp-${PLAT}.mk)
ifeq (,${TSP_PLAT_MAKEFILE})
$(error TSP is not supported on platform ${PLAT})
else
include ${TSP_PLAT_MAKEFILE}
endif

View File

@@ -0,0 +1,117 @@
/*
* Copyright (c) 2014-2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <inttypes.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <bl32/tsp/tsp.h>
#include <common/debug.h>
#include <plat/common/platform.h>
#include "tsp_private.h"
/*******************************************************************************
* This function updates the TSP statistics for S-EL1 interrupts handled
* synchronously i.e the ones that have been handed over by the TSPD. It also
* keeps count of the number of times control was passed back to the TSPD
* after handling the interrupt. In the future it will be possible that the
* TSPD hands over an S-EL1 interrupt to the TSP but does not expect it to
* return execution. This statistic will be useful to distinguish between these
* two models of synchronous S-EL1 interrupt handling. The 'elr_el3' parameter
* contains the address of the instruction in normal world where this S-EL1
* interrupt was generated.
******************************************************************************/
void tsp_update_sync_sel1_intr_stats(uint32_t type, uint64_t elr_el3)
{
uint32_t linear_id = plat_my_core_pos();
tsp_stats[linear_id].sync_sel1_intr_count++;
if (type == TSP_HANDLE_SEL1_INTR_AND_RETURN)
tsp_stats[linear_id].sync_sel1_intr_ret_count++;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx sync s-el1 interrupt request from 0x%" PRIx64 "\n",
read_mpidr(), elr_el3);
VERBOSE("TSP: cpu 0x%lx: %d sync s-el1 interrupt requests,"
" %d sync s-el1 interrupt returns\n",
read_mpidr(),
tsp_stats[linear_id].sync_sel1_intr_count,
tsp_stats[linear_id].sync_sel1_intr_ret_count);
spin_unlock(&console_lock);
#endif
}
/******************************************************************************
* This function is invoked when a non S-EL1 interrupt is received and causes
* the preemption of TSP. This function returns TSP_PREEMPTED and results
* in the control being handed over to EL3 for handling the interrupt.
*****************************************************************************/
int32_t tsp_handle_preemption(void)
{
uint32_t linear_id = plat_my_core_pos();
tsp_stats[linear_id].preempt_intr_count++;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx: %d preempt interrupt requests\n",
read_mpidr(), tsp_stats[linear_id].preempt_intr_count);
spin_unlock(&console_lock);
#endif
return TSP_PREEMPTED;
}
/*******************************************************************************
* TSP interrupt handler is called as a part of both synchronous and
* asynchronous handling of TSP interrupts. Currently the physical timer
* interrupt is the only S-EL1 interrupt that this handler expects. It returns
* 0 upon successfully handling the expected interrupt and all other
* interrupts are treated as normal world or EL3 interrupts.
******************************************************************************/
int32_t tsp_common_int_handler(void)
{
uint32_t linear_id = plat_my_core_pos(), id;
/*
* Get the highest priority pending interrupt id and see if it is the
* secure physical generic timer interrupt in which case, handle it.
* Otherwise throw this interrupt at the EL3 firmware.
*
* There is a small time window between reading the highest priority
* pending interrupt and acknowledging it during which another
* interrupt of higher priority could become the highest pending
* interrupt. This is not expected to happen currently for TSP.
*/
id = plat_ic_get_pending_interrupt_id();
/* TSP can only handle the secure physical timer interrupt */
if (id != TSP_IRQ_SEC_PHY_TIMER)
return tsp_handle_preemption();
/*
* Acknowledge and handle the secure timer interrupt. Also sanity check
* if it has been preempted by another interrupt through an assertion.
*/
id = plat_ic_acknowledge_interrupt();
assert(id == TSP_IRQ_SEC_PHY_TIMER);
tsp_generic_timer_handler();
plat_ic_end_of_interrupt(id);
/* Update the statistics and print some messages */
tsp_stats[linear_id].sel1_intr_count++;
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
spin_lock(&console_lock);
VERBOSE("TSP: cpu 0x%lx handled S-EL1 interrupt %d\n",
read_mpidr(), id);
VERBOSE("TSP: cpu 0x%lx: %d S-EL1 requests\n",
read_mpidr(), tsp_stats[linear_id].sel1_intr_count);
spin_unlock(&console_lock);
#endif
return 0;
}

Some files were not shown because too many files have changed in this diff Show More