mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #10469 from ARMmbed/release-candidate
Release candidate for mbed-os-5.12.2mbed-os-5.12 mbed-os-5.12.2
commit
cfa7938a4d
337
.travis.yml
337
.travis.yml
|
@ -14,59 +14,103 @@
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
language: python
|
language: sh
|
||||||
python: 2.7
|
os: linux
|
||||||
|
dist: xenial
|
||||||
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
global:
|
global:
|
||||||
- >
|
- deps_url="https://mbed-os-ci.s3-eu-west-1.amazonaws.com/jenkins-ci/deps"
|
||||||
STATUS=$'curl -so/dev/null --user "$MBED_BOT" --request POST
|
- deps_dir="${HOME}/.cache/deps"
|
||||||
https://api.github.com/repos/$TRAVIS_REPO_SLUG/statuses/${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}
|
|
||||||
--data @- << DATA\n{
|
|
||||||
"state": "$0",
|
|
||||||
"description": "$1",
|
|
||||||
"context": "travis-ci/$NAME",
|
|
||||||
"target_url": "https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID"
|
|
||||||
}\nDATA'
|
|
||||||
|
|
||||||
cache:
|
cache:
|
||||||
pip: true
|
pip: true
|
||||||
directories:
|
directories:
|
||||||
- $HOME/.cache/apt
|
- ${HOME}/.cache/deps
|
||||||
- $HOME/gcc-arm-none-eabi-6-2017-q2-update
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- bash -c "$STATUS" pending "Local $NAME testing is in progress"
|
- source tools/test/travis-ci/functions.sh
|
||||||
# Make sure pipefail
|
- set_status "pending" "Test started."
|
||||||
- set -o pipefail
|
|
||||||
# Setup apt to cache
|
|
||||||
- mkdir -p $HOME/.cache/apt/partial
|
|
||||||
- sudo rm -rf /var/cache/apt/archives
|
|
||||||
- sudo ln -s $HOME/.cache/apt /var/cache/apt/archives
|
|
||||||
# Setup ppa to make sure arm-none-eabi-gcc is correct version
|
|
||||||
- sudo add-apt-repository -y ppa:team-gcc-arm-embedded/ppa
|
|
||||||
- sudo add-apt-repository -y ppa:deadsnakes/ppa
|
|
||||||
# workaround for https://travis-ci.community/t/then-sudo-apt-get-update-failed-public-key-is-not-available-no-pubkey-6b05f25d762e3157-in-ubuntu-xenial/1728
|
|
||||||
- sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 762E3157
|
|
||||||
# Loop until update succeeds (timeouts can occur)
|
|
||||||
- travis_retry $(! sudo apt-get update 2>&1 |grep Failed)
|
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- bash -c "$STATUS" success "Local $NAME testing has passed"
|
- set_status "success" "Success!"
|
||||||
|
|
||||||
after_failure:
|
after_failure:
|
||||||
- bash -c "$STATUS" failure "Local $NAME testing has failed"
|
- set_status "failure" "Test failed."
|
||||||
|
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- env:
|
|
||||||
- NAME=docs
|
### Basic Tests ###
|
||||||
|
- &basic-vm
|
||||||
|
stage: "Basic"
|
||||||
|
name: "file attributes"
|
||||||
|
env: NAME=gitattributestest
|
||||||
|
script:
|
||||||
|
- git diff --exit-code
|
||||||
|
|
||||||
|
- <<: *basic-vm
|
||||||
|
name: "license check"
|
||||||
|
env: NAME=licence_check
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
! grep --recursive --max-count=100 --ignore-case --exclude .travis.yml \
|
||||||
|
"gnu general\|gnu lesser\|lesser general\|public license"
|
||||||
|
|
||||||
|
- <<: *basic-vm
|
||||||
|
name: "include check"
|
||||||
|
env: NAME=include_check
|
||||||
|
script:
|
||||||
|
- |
|
||||||
|
! git grep '^#include\s["'"']mbed.h['"'"]$' -- '*.c' '*.h' '*.cpp' '*.hpp' \
|
||||||
|
':!*platform_mbed.h' ':!*TESTS/*' ':!TEST_APPS/' ':!UNITTESTS/' \
|
||||||
|
':!*tests/*' ':!*targets/*' ':!*TARGET_*' ':!*unsupported/*'
|
||||||
|
|
||||||
|
|
||||||
|
### Docs Tests ###
|
||||||
|
- &docs-vm
|
||||||
|
stage: "Docs"
|
||||||
|
name: "astyle"
|
||||||
|
env: NAME=astyle
|
||||||
|
install:
|
||||||
|
- >-
|
||||||
|
curl -L0 https://mbed-os.s3-eu-west-1.amazonaws.com/builds/deps/astyle_3.1_linux.tar.gz --output astyle.tar.gz;
|
||||||
|
mkdir -p BUILD && tar xf astyle.tar.gz -C BUILD;
|
||||||
|
cd BUILD/astyle/build/gcc;
|
||||||
|
make;
|
||||||
|
export PATH="${PWD}/bin:${PATH}";
|
||||||
|
cd -
|
||||||
|
- astyle --version
|
||||||
|
# Fetch remaining information needed for branch comparison
|
||||||
|
- git fetch --all --unshallow --tags
|
||||||
|
- git fetch origin "${TRAVIS_BRANCH}"
|
||||||
|
script:
|
||||||
|
- >-
|
||||||
|
git diff --name-only --diff-filter=d FETCH_HEAD..HEAD \
|
||||||
|
| ( grep '.\(c\|cpp\|h\|hpp\)$' || true ) \
|
||||||
|
| ( grep -v -f .astyleignore || true ) \
|
||||||
|
| while read file; do astyle -n --options=.astylerc "${file}"; done
|
||||||
|
- git diff --exit-code --diff-filter=d --color
|
||||||
|
|
||||||
|
- <<: *docs-vm
|
||||||
|
name: "spellcheck"
|
||||||
|
env: NAME=doxy-spellcheck
|
||||||
|
install:
|
||||||
|
- source_pkg aspell
|
||||||
|
script:
|
||||||
|
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh drivers
|
||||||
|
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh platform
|
||||||
|
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh events
|
||||||
|
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh rtos
|
||||||
|
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh features/netsocket
|
||||||
|
|
||||||
|
- <<: *docs-vm
|
||||||
|
name: "doxygen"
|
||||||
|
env: NAME=docs
|
||||||
install:
|
install:
|
||||||
# Install dependencies
|
|
||||||
- sudo apt-get install doxygen
|
|
||||||
# Print versions we use
|
|
||||||
- doxygen --version
|
|
||||||
before_script:
|
|
||||||
# Build doxygen
|
# Build doxygen
|
||||||
- >
|
- >
|
||||||
(git clone --depth=1 --single-branch --branch Release_1_8_14 https://github.com/doxygen/doxygen;
|
(git clone --depth=1 --single-branch --branch Release_1_8_14 https://github.com/doxygen/doxygen;
|
||||||
|
@ -99,14 +143,19 @@ matrix:
|
||||||
find -name "*.s" | tee BUILD/badasm |
|
find -name "*.s" | tee BUILD/badasm |
|
||||||
sed -e "s/^/Bad Assembler file name found: /" && [ ! -s BUILD/badasm ]
|
sed -e "s/^/Bad Assembler file name found: /" && [ ! -s BUILD/badasm ]
|
||||||
|
|
||||||
- &tools-pytest
|
|
||||||
|
### Python Tests ###
|
||||||
|
- &pytools-vm
|
||||||
|
stage: "Pytest"
|
||||||
|
name: "tools-py27"
|
||||||
env: NAME=tools-py2.7
|
env: NAME=tools-py2.7
|
||||||
|
language: python
|
||||||
python: 2.7
|
python: 2.7
|
||||||
install:
|
install:
|
||||||
# Install dependencies
|
# Install gcc
|
||||||
- sudo apt-get install gcc-arm-embedded
|
- source_pkg gcc
|
||||||
- arm-none-eabi-gcc --version
|
- arm-none-eabi-gcc --version
|
||||||
# Add additional dependencies specific for testing
|
# Install additional python modules
|
||||||
- python --version
|
- python --version
|
||||||
- |-
|
- |-
|
||||||
tr -d ' ' >> requirements.txt <<< "
|
tr -d ' ' >> requirements.txt <<< "
|
||||||
|
@ -117,7 +166,8 @@ matrix:
|
||||||
coverage>=4.5,<5
|
coverage>=4.5,<5
|
||||||
coveralls>=1.5,<2
|
coveralls>=1.5,<2
|
||||||
"
|
"
|
||||||
# ... and install.
|
- python -m pip install --upgrade pip==18.1
|
||||||
|
- python -m pip install --upgrade setuptools==40.4.3
|
||||||
- pip install -r requirements.txt
|
- pip install -r requirements.txt
|
||||||
- pip list --verbose
|
- pip list --verbose
|
||||||
script:
|
script:
|
||||||
|
@ -126,118 +176,92 @@ matrix:
|
||||||
- python tools/test/pylint.py
|
- python tools/test/pylint.py
|
||||||
- coverage run -a tools/project.py -S | sed -n '/^Total/p'
|
- coverage run -a tools/project.py -S | sed -n '/^Total/p'
|
||||||
- coverage html
|
- coverage html
|
||||||
after_success:
|
|
||||||
# Coverage for tools
|
|
||||||
- coveralls
|
- coveralls
|
||||||
# Report success since we have overridden default behavior
|
|
||||||
- bash -c "$STATUS" success "Local $NAME testing has passed"
|
|
||||||
|
|
||||||
- env:
|
- <<: *pytools-vm
|
||||||
- NAME=doxy-spellcheck
|
name: "tools-py35"
|
||||||
|
|
||||||
install:
|
|
||||||
- sudo apt-get install aspell
|
|
||||||
|
|
||||||
script:
|
|
||||||
# Run local testing on header file doxy
|
|
||||||
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh drivers
|
|
||||||
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh platform
|
|
||||||
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh events
|
|
||||||
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh rtos
|
|
||||||
- ./tools/test/travis-ci/doxy-spellchecker/spell.sh features/netsocket
|
|
||||||
|
|
||||||
after_success:
|
|
||||||
# Coverage for tools
|
|
||||||
- coveralls
|
|
||||||
# Report success since we have overridden default behavior
|
|
||||||
- bash -c "$STATUS" success "Local $NAME testing has passed"
|
|
||||||
|
|
||||||
- <<: *tools-pytest
|
|
||||||
env: NAME=tools-py3.5
|
env: NAME=tools-py3.5
|
||||||
python: 3.5
|
python: 3.5
|
||||||
|
|
||||||
- <<: *tools-pytest
|
- <<: *pytools-vm
|
||||||
|
name: "tools-py36"
|
||||||
env: NAME=tools-py3.6
|
env: NAME=tools-py3.6
|
||||||
python: 3.6
|
python: 3.6
|
||||||
|
|
||||||
- <<: *tools-pytest
|
- <<: *pytools-vm
|
||||||
|
name: "tools-py37"
|
||||||
env: NAME=tools-py3.7
|
env: NAME=tools-py3.7
|
||||||
python: 3.7
|
python: 3.7
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- NAME=astyle
|
### Extended Tests ###
|
||||||
|
- &extended-vm
|
||||||
|
stage: "Extended"
|
||||||
|
name: "psa autogen"
|
||||||
|
env: NAME=psa-autogen
|
||||||
|
language: python
|
||||||
|
python: 3.7
|
||||||
install:
|
install:
|
||||||
- >-
|
# Install gcc
|
||||||
curl -L0 https://mbed-os-ci.s3-eu-west-1.amazonaws.com/jenkins-ci/deps/astyle_3.1_linux.tar.gz --output astyle.tar.gz;
|
- source_pkg gcc
|
||||||
mkdir -p BUILD && tar xf astyle.tar.gz -C BUILD;
|
|
||||||
cd BUILD/astyle/build/gcc;
|
|
||||||
make;
|
|
||||||
export PATH=$PWD/bin:$PATH;
|
|
||||||
cd -
|
|
||||||
- astyle --version
|
|
||||||
# Fetch remaining information needed for branch comparison
|
|
||||||
- git fetch --all --unshallow --tags
|
|
||||||
- git fetch origin "${TRAVIS_BRANCH}"
|
|
||||||
script:
|
|
||||||
- >-
|
|
||||||
git diff --name-only --diff-filter=d FETCH_HEAD..HEAD \
|
|
||||||
| ( grep '.\(c\|cpp\|h\|hpp\)$' || true ) \
|
|
||||||
| ( grep -v -f .astyleignore || true ) \
|
|
||||||
| while read file; do astyle -n --options=.astylerc "${file}"; done
|
|
||||||
- git diff --exit-code --diff-filter=d --color
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- NAME=events
|
|
||||||
- EVENTS=events
|
|
||||||
install:
|
|
||||||
# Install dependencies
|
|
||||||
- sudo apt-get install gcc-arm-embedded
|
|
||||||
- pip install -r requirements.txt
|
|
||||||
# Print versions we use
|
|
||||||
- arm-none-eabi-gcc --version
|
- arm-none-eabi-gcc --version
|
||||||
- gcc --version
|
# Install python modules
|
||||||
- python --version
|
- python -m pip install --upgrade pip==18.1
|
||||||
|
- python -m pip install --upgrade setuptools==40.4.3
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
- pip list --verbose
|
||||||
|
script:
|
||||||
|
- python tools/psa/generate_partition_code.py
|
||||||
|
- git diff --exit-code
|
||||||
|
|
||||||
|
- <<: *extended-vm
|
||||||
|
name: "events"
|
||||||
|
env: NAME=events EVENTS=events
|
||||||
script:
|
script:
|
||||||
# Check that example compiles
|
# Check that example compiles
|
||||||
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp
|
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' ${EVENTS}/README.md > main.cpp
|
||||||
- python tools/make.py -t GCC_ARM -m K64F --source=. --build=BUILD/K64F/GCC_ARM -j0
|
- python tools/make.py -t GCC_ARM -m K64F --source=. --build=BUILD/K64F/GCC_ARM -j0
|
||||||
# Check that example compiles without rtos
|
# Check that example compiles without rtos
|
||||||
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp
|
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' ${EVENTS}/README.md > main.cpp
|
||||||
- rm -r rtos usb features/cellular features/netsocket features/nanostack features/lwipstack features/frameworks/greentea-client features/frameworks/utest features/frameworks/unity components BUILD
|
- |
|
||||||
|
rm -r rtos usb features/cellular features/netsocket features/nanostack \
|
||||||
|
features/lwipstack features/frameworks/greentea-client \
|
||||||
|
features/frameworks/utest features/frameworks/unity components BUILD
|
||||||
- python tools/make.py -t GCC_ARM -m DISCO_F401VC --source=. --build=BUILD/DISCO_F401VC/GCC_ARM -j0
|
- python tools/make.py -t GCC_ARM -m DISCO_F401VC --source=. --build=BUILD/DISCO_F401VC/GCC_ARM -j0
|
||||||
# Run local equeue tests
|
# Run local equeue tests
|
||||||
- make -C $EVENTS/equeue test
|
- make -C ${EVENTS}/equeue test
|
||||||
# Run profiling tests
|
# Run profiling tests
|
||||||
- make -C $EVENTS/equeue prof | tee prof
|
- make -C ${EVENTS}/equeue prof | tee prof
|
||||||
after_success:
|
after_success:
|
||||||
# update status if we succeeded, compare with master if possible
|
# Update status, comparing with master if possible.
|
||||||
- |
|
- |
|
||||||
CURR=$(grep -o '[0-9]\+ cycles' prof | awk '{sum += $1} END {print sum}')
|
CURR=$(grep -o '[0-9]\+ cycles' prof | awk '{sum += $1} END {print sum}')
|
||||||
PREV=$(curl -u "$MBED_BOT" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
|
PREV=$(curl -u "${MBED_BOT}" https://api.github.com/repos/${TRAVIS_REPO_SLUG}/status/master \
|
||||||
| jq -re "select(.sha != \"$TRAVIS_COMMIT\")
|
| jq -re "select(.sha != \"${TRAVIS_COMMIT}\")
|
||||||
| .statuses[] | select(.context == \"travis-ci/$NAME\").description
|
| .statuses[] | select(.context == \"travis-ci/${NAME}\").description
|
||||||
| capture(\"runtime is (?<runtime>[0-9]+)\").runtime" \
|
| capture(\"runtime is (?<runtime>[0-9]+)\").runtime" \
|
||||||
|| echo 0)
|
|| echo 0)
|
||||||
|
|
||||||
STATUSM="Passed, runtime is ${CURR} cycles"
|
delta=""
|
||||||
if [ "$PREV" -ne 0 ]
|
[ "${PREV}" -ne 0 ] && delta="($(printf "%+d" "$(( ${CURR} - ${PREV} ))" cycles)"
|
||||||
then
|
|
||||||
STATUSM="$STATUSM ($(python -c "print '%+d' % ($CURR-$PREV)") cycles)"
|
|
||||||
fi
|
|
||||||
- bash -c "$STATUS" success "$STATUSM"
|
|
||||||
|
|
||||||
- env:
|
set_status "success" "Success! Runtime is ${CURR} cycles. ${delta}"
|
||||||
- NAME=littlefs
|
|
||||||
- LITTLEFS=features/storage/filesystem/littlefs
|
- <<: *extended-vm
|
||||||
|
name: "littlefs"
|
||||||
|
env: NAME=littlefs LITTLEFS=features/storage/filesystem/littlefs
|
||||||
install:
|
install:
|
||||||
# Install dependencies
|
# Install gcc
|
||||||
- sudo apt-get install gcc-arm-embedded fuse libfuse-dev
|
- source_pkg gcc
|
||||||
- pip install -r requirements.txt
|
|
||||||
# Print versions
|
|
||||||
- arm-none-eabi-gcc --version
|
- arm-none-eabi-gcc --version
|
||||||
- gcc --version
|
# Install python modules
|
||||||
- python --version
|
- python -m pip install --upgrade pip==18.1
|
||||||
|
- python -m pip install --upgrade setuptools==40.4.3
|
||||||
|
- pip install -r requirements.txt
|
||||||
|
- pip list --verbose
|
||||||
|
# Install test-specific packages
|
||||||
|
- source_pkg fuse
|
||||||
|
- source_pkg libfuse-dev
|
||||||
- fusermount --version
|
- fusermount --version
|
||||||
before_script:
|
before_script:
|
||||||
# Setup and patch littlefs-fuse
|
# Setup and patch littlefs-fuse
|
||||||
|
@ -245,7 +269,7 @@ matrix:
|
||||||
- git -C littlefs_fuse checkout 3f1ed6e37799e49e3710830dc6abb926d5503cf2
|
- git -C littlefs_fuse checkout 3f1ed6e37799e49e3710830dc6abb926d5503cf2
|
||||||
- echo '*' > littlefs_fuse/.mbedignore
|
- echo '*' > littlefs_fuse/.mbedignore
|
||||||
- rm -rf littlefs_fuse/littlefs/*
|
- rm -rf littlefs_fuse/littlefs/*
|
||||||
- cp -r $(git ls-tree --name-only HEAD $LITTLEFS/littlefs/) littlefs_fuse/littlefs
|
- cp -r $(git ls-tree --name-only HEAD ${LITTLEFS}/littlefs/) littlefs_fuse/littlefs
|
||||||
# Create file-backed disk
|
# Create file-backed disk
|
||||||
- mkdir MOUNT
|
- mkdir MOUNT
|
||||||
- sudo chmod a+rw /dev/loop0
|
- sudo chmod a+rw /dev/loop0
|
||||||
|
@ -255,74 +279,43 @@ matrix:
|
||||||
script:
|
script:
|
||||||
# Check that example compiles
|
# Check that example compiles
|
||||||
- export CFLAGS="-Werror -Wno-format"
|
- export CFLAGS="-Werror -Wno-format"
|
||||||
- sed -n '/``` c++/,/```/{/```/d;p;}' $LITTLEFS/README.md > main.cpp
|
- sed -n '/``` c++/,/```/{/```/d;p;}' ${LITTLEFS}/README.md > main.cpp
|
||||||
- python tools/make.py -t GCC_ARM -m K82F --source=. --build=BUILD/K82F/GCC_ARM -j0
|
- python tools/make.py -t GCC_ARM -m K82F --source=. --build=BUILD/K82F/GCC_ARM -j0
|
||||||
# Run local littlefs tests
|
# Run local littlefs tests
|
||||||
- make -C$LITTLEFS/littlefs test QUIET=1
|
- make -C${LITTLEFS}/littlefs test QUIET=1
|
||||||
# Run local littlefs tests with set of variations
|
# Run local littlefs tests with set of variations
|
||||||
- make -C$LITTLEFS/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=64 -DLFS_PROG_SIZE=64"
|
- make -C${LITTLEFS}/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=64 -DLFS_PROG_SIZE=64"
|
||||||
- make -C$LITTLEFS/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1"
|
- make -C${LITTLEFS}/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1"
|
||||||
- make -C$LITTLEFS/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512"
|
- make -C${LITTLEFS}/littlefs test QUIET=1 CFLAGS+="-DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512"
|
||||||
- make -C$LITTLEFS/littlefs test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048"
|
- make -C${LITTLEFS}/littlefs test QUIET=1 CFLAGS+="-DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048"
|
||||||
- make -C$LITTLEFS/littlefs clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS"
|
- make -C${LITTLEFS}/littlefs clean test QUIET=1 CFLAGS+="-DLFS_NO_INTRINSICS"
|
||||||
# Self-hosting littlefs fuzz test with littlefs-fuse
|
# Self-hosting littlefs fuzz test with littlefs-fuse
|
||||||
- make -Clittlefs_fuse
|
- make -Clittlefs_fuse
|
||||||
- littlefs_fuse/lfs --format /dev/loop0
|
- littlefs_fuse/lfs --format /dev/loop0
|
||||||
- littlefs_fuse/lfs /dev/loop0 MOUNT
|
- littlefs_fuse/lfs /dev/loop0 MOUNT
|
||||||
- ls MOUNT
|
- ls MOUNT
|
||||||
- mkdir MOUNT/littlefs
|
- mkdir MOUNT/littlefs
|
||||||
- cp -r $(git ls-tree --name-only HEAD $LITTLEFS/littlefs/) MOUNT/littlefs
|
- cp -r $(git ls-tree --name-only HEAD ${LITTLEFS}/littlefs/) MOUNT/littlefs
|
||||||
- ls MOUNT/littlefs
|
- ls MOUNT/littlefs
|
||||||
- CFLAGS="-Wno-format" make -CMOUNT/littlefs -B test_dirs test_files QUIET=1
|
- CFLAGS="-Wno-format" make -CMOUNT/littlefs -B test_dirs test_files QUIET=1
|
||||||
# Compile and find the code size with smallest configuration
|
# Compile and find the code size with smallest configuration
|
||||||
- cd $TRAVIS_BUILD_DIR/$LITTLEFS/littlefs
|
- cd ${TRAVIS_BUILD_DIR}/${LITTLEFS}/littlefs
|
||||||
- make clean size
|
- make clean size
|
||||||
CC='arm-none-eabi-gcc -mthumb'
|
CC='arm-none-eabi-gcc -mthumb'
|
||||||
OBJ="$(ls lfs*.o | tr '\n' ' ')"
|
OBJ="$(ls lfs*.o | tr '\n' ' ')"
|
||||||
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
|
CFLAGS+="-DLFS_NO_ASSERT -DLFS_NO_DEBUG -DLFS_NO_WARN -DLFS_NO_ERROR"
|
||||||
| tee sizes
|
| tee sizes
|
||||||
after_success:
|
after_success:
|
||||||
# update status if we succeeded, compare with master if possible
|
# Update status, comparing with master if possible.
|
||||||
- |
|
- |
|
||||||
CURR=$(tail -n1 sizes | awk '{print $1}')
|
CURR=$(tail -n1 sizes | awk '{print $1}')
|
||||||
PREV=$(curl -u "$MBED_BOT" https://api.github.com/repos/$TRAVIS_REPO_SLUG/status/master \
|
PREV=$(curl -u "${MBED_BOT}" https://api.github.com/repos/${TRAVIS_REPO_SLUG}/status/master \
|
||||||
| jq -re "select(.sha != \"$TRAVIS_COMMIT\")
|
| jq -re "select(.sha != \"${TRAVIS_COMMIT}\")
|
||||||
| .statuses[] | select(.context == \"travis-ci/$NAME\").description
|
| .statuses[] | select(.context == \"travis-ci/${NAME}\").description
|
||||||
| capture(\"code size is (?<size>[0-9]+)\").size" \
|
| capture(\"code size is (?<size>[0-9]+)\").size" \
|
||||||
|| echo 0)
|
|| echo 0)
|
||||||
|
|
||||||
STATUSM="Passed, code size is ${CURR}B"
|
delta=""
|
||||||
if [ "$PREV" -ne 0 ]
|
[ "${PREV}" -ne 0 ] && delta="($(printf "%+0.2f%%" "$(<<< "100 * ((${CURR} - ${PREV})/${PREV})" bc -l)"))"
|
||||||
then
|
|
||||||
STATUSM="$STATUSM ($(python -c "print '%+.2f' % (100*($CURR-$PREV)/$PREV.0)")%)"
|
|
||||||
fi
|
|
||||||
- bash -c "$STATUS" success "$STATUSM"
|
|
||||||
|
|
||||||
- env:
|
set_status "success" "Success! Code size is ${CURR}B. ${delta}"
|
||||||
- NAME=gitattributestest
|
|
||||||
script:
|
|
||||||
# Check that no changes after clone. This check that .gitattributes is used right way.
|
|
||||||
- git diff --exit-code
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- NAME=licence_check
|
|
||||||
script:
|
|
||||||
- >-
|
|
||||||
! grep --recursive --max-count=100 --ignore-case --exclude .travis.yml \
|
|
||||||
"gnu general\|gnu lesser\|lesser general\|public license"
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- NAME=include_check
|
|
||||||
script:
|
|
||||||
- echo 'Checking that there are no '#include "mbed.h"' in code where it should not be'
|
|
||||||
- |
|
|
||||||
! git grep '^#include\s["'"']mbed.h['"'"]$' -- '*.c' '*.h' '*.cpp' '*.hpp' \
|
|
||||||
':!*platform_mbed.h' ':!*TESTS/*' ':!TEST_APPS/' ':!UNITTESTS/' \
|
|
||||||
':!*tests/*' ':!*targets/*' ':!*TARGET_*' ':!*unsupported/*'
|
|
||||||
|
|
||||||
- env:
|
|
||||||
- NAME=psa-autogen
|
|
||||||
script:
|
|
||||||
# Run SPM code generators and check that changes are not needed
|
|
||||||
- python tools/psa/generate_partition_code.py
|
|
||||||
- git diff --exit-code
|
|
||||||
|
|
|
@ -50,3 +50,4 @@ The Python modules used by Mbed tools are used under the following licenses:
|
||||||
- [pycryptodome](https://pypi.org/project/pycryptodome) - BSD-2-Clause
|
- [pycryptodome](https://pypi.org/project/pycryptodome) - BSD-2-Clause
|
||||||
- [pyusb](https://pypi.org/project/pyusb/) - Apache-2.0
|
- [pyusb](https://pypi.org/project/pyusb/) - Apache-2.0
|
||||||
- [cmsis-pack-manager](https://pypi.org/project/cmsis-pack-manager) - Apache-2.0
|
- [cmsis-pack-manager](https://pypi.org/project/cmsis-pack-manager) - Apache-2.0
|
||||||
|
- [hidapi](https://pypi.org/project/hidapi/) - BSD-style
|
||||||
|
|
|
@ -0,0 +1,566 @@
|
||||||
|
"""
|
||||||
|
mbed SDK
|
||||||
|
Copyright (c) 2019 ARM Limited
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
from __future__ import print_function
|
||||||
|
import functools
|
||||||
|
import time
|
||||||
|
import threading
|
||||||
|
import uuid
|
||||||
|
import mbed_host_tests
|
||||||
|
import usb.core
|
||||||
|
from usb.util import (
|
||||||
|
CTRL_IN,
|
||||||
|
CTRL_OUT,
|
||||||
|
CTRL_TYPE_STANDARD,
|
||||||
|
CTRL_TYPE_CLASS,
|
||||||
|
CTRL_RECIPIENT_DEVICE,
|
||||||
|
CTRL_RECIPIENT_INTERFACE,
|
||||||
|
DESC_TYPE_CONFIG,
|
||||||
|
build_request_type)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import hid
|
||||||
|
except ImportError:
|
||||||
|
CYTHON_HIDAPI_PRESENT = False
|
||||||
|
else:
|
||||||
|
CYTHON_HIDAPI_PRESENT = True
|
||||||
|
|
||||||
|
# USB device -- device classes
|
||||||
|
USB_CLASS_HID = 0x03
|
||||||
|
|
||||||
|
# USB device -- standard requests
|
||||||
|
USB_REQUEST_GET_DESCRIPTOR = 0x06
|
||||||
|
|
||||||
|
# USB device -- HID class requests
|
||||||
|
HID_REQUEST_GET_REPORT = 0x01
|
||||||
|
HID_REQUEST_SET_REPORT = 0x09
|
||||||
|
HID_REQUEST_GET_IDLE = 0x02
|
||||||
|
HID_REQUEST_SET_IDLE = 0x0A
|
||||||
|
HID_REQUEST_GET_PROTOCOL = 0x03
|
||||||
|
HID_REQUEST_SET_PROTOCOL = 0x0B
|
||||||
|
|
||||||
|
# USB device -- HID class descriptors
|
||||||
|
DESC_TYPE_HID_HID = 0x21
|
||||||
|
DESC_TYPE_HID_REPORT = 0x22
|
||||||
|
DESC_TYPE_HID_PHYSICAL = 0x23
|
||||||
|
|
||||||
|
# USB device -- HID class descriptor lengths
|
||||||
|
DESC_LEN_HID_HID = 0x09
|
||||||
|
|
||||||
|
# USB device -- descriptor fields offsets
|
||||||
|
DESC_OFFSET_BLENGTH = 0
|
||||||
|
DESC_OFFSET_BDESCRIPTORTYPE = 1
|
||||||
|
|
||||||
|
# USB device -- HID subclasses
|
||||||
|
HID_SUBCLASS_NONE = 0
|
||||||
|
HID_SUBCLASS_BOOT = 1
|
||||||
|
|
||||||
|
# USB device -- HID protocols
|
||||||
|
HID_PROTOCOL_NONE = 0
|
||||||
|
HID_PROTOCOL_KEYBOARD = 1
|
||||||
|
HID_PROTOCOL_MOUSE = 2
|
||||||
|
|
||||||
|
# Greentea message keys used for callbacks
|
||||||
|
MSG_KEY_DEVICE_READY = 'dev_ready'
|
||||||
|
MSG_KEY_HOST_READY = 'host_ready'
|
||||||
|
MSG_KEY_SERIAL_NUMBER = 'usb_dev_sn'
|
||||||
|
MSG_KEY_TEST_GET_DESCRIPTOR_HID = 'test_get_desc_hid'
|
||||||
|
MSG_KEY_TEST_GET_DESCRIPTOR_CFG = 'test_get_desc_cfg'
|
||||||
|
MSG_KEY_TEST_REQUESTS = 'test_requests'
|
||||||
|
MSG_KEY_TEST_RAW_IO = 'test_raw_io'
|
||||||
|
|
||||||
|
# Greentea message keys used to notify DUT of test status
|
||||||
|
MSG_KEY_TEST_CASE_FAILED = 'fail'
|
||||||
|
MSG_KEY_TEST_CASE_PASSED = 'pass'
|
||||||
|
MSG_VALUE_DUMMY = '0'
|
||||||
|
MSG_VALUE_NOT_SUPPORTED = 'not_supported'
|
||||||
|
|
||||||
|
# Constants for the tests.
|
||||||
|
KEYBOARD_IDLE_RATE_TO_SET = 0x00 # Duration = 0 (indefinite)
|
||||||
|
HID_PROTOCOL_TO_SET = 0x01 # Protocol = 1 (Report Protocol)
|
||||||
|
RAW_IO_REPS = 16 # Number of loopback test reps.
|
||||||
|
|
||||||
|
|
||||||
|
def build_get_desc_value(desc_type, desc_index):
|
||||||
|
"""Build and return a wValue field for control requests."""
|
||||||
|
return (desc_type << 8) | desc_index
|
||||||
|
|
||||||
|
|
||||||
|
def usb_hid_path(serial_number):
|
||||||
|
"""Get a USB HID device system path based on the serial number."""
|
||||||
|
if not CYTHON_HIDAPI_PRESENT:
|
||||||
|
return None
|
||||||
|
for device_info in hid.enumerate(): # pylint: disable=no-member
|
||||||
|
if device_info.get('serial_number') == serial_number: # pylint: disable=not-callable
|
||||||
|
return device_info['path']
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_descriptor_types(desc):
|
||||||
|
"""Return a list of all bDescriptorType values found in desc.
|
||||||
|
|
||||||
|
desc is expected to be a sequence of bytes, i.e. array.array('B')
|
||||||
|
returned from usb.core.
|
||||||
|
|
||||||
|
From the USB 2.0 spec, paragraph 9.5:
|
||||||
|
Each descriptor begins with a byte-wide field that contains the total
|
||||||
|
number of bytes in the descriptor followed by a byte-wide field that
|
||||||
|
identifies the descriptor type.
|
||||||
|
"""
|
||||||
|
tmp_desc = desc[DESC_OFFSET_BLENGTH:]
|
||||||
|
desc_types = []
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
bLength = tmp_desc[DESC_OFFSET_BLENGTH] # pylint: disable=invalid-name
|
||||||
|
bDescriptorType = tmp_desc[DESC_OFFSET_BDESCRIPTORTYPE] # pylint: disable=invalid-name
|
||||||
|
desc_types.append(int(bDescriptorType))
|
||||||
|
tmp_desc = tmp_desc[int(bLength):]
|
||||||
|
except IndexError:
|
||||||
|
break
|
||||||
|
return desc_types
|
||||||
|
|
||||||
|
|
||||||
|
def get_hid_descriptor_parts(hid_descriptor):
|
||||||
|
"""Return bNumDescriptors, bDescriptorType, wDescriptorLength from hid_descriptor."""
|
||||||
|
err_msg = 'Invalid HID class descriptor'
|
||||||
|
try:
|
||||||
|
if hid_descriptor[1] != DESC_TYPE_HID_HID:
|
||||||
|
raise TypeError(err_msg)
|
||||||
|
bNumDescriptors = int(hid_descriptor[5]) # pylint: disable=invalid-name
|
||||||
|
bDescriptorType = int(hid_descriptor[6]) # pylint: disable=invalid-name
|
||||||
|
wDescriptorLength = int((hid_descriptor[8] << 8) | hid_descriptor[7]) # pylint: disable=invalid-name
|
||||||
|
except (IndexError, ValueError):
|
||||||
|
raise TypeError(err_msg)
|
||||||
|
return bNumDescriptors, bDescriptorType, wDescriptorLength
|
||||||
|
|
||||||
|
|
||||||
|
def get_usbhid_dev_type(intf):
|
||||||
|
"""Return a name of the HID device class type for intf."""
|
||||||
|
if not isinstance(intf, usb.core.Interface):
|
||||||
|
return None
|
||||||
|
if intf.bInterfaceClass != USB_CLASS_HID:
|
||||||
|
# USB Device Class Definition for HID, v1.11, paragraphs 4.1, 4.2 & 4.3:
|
||||||
|
# the class is specified in the Interface descriptor
|
||||||
|
# and not the Device descriptor.
|
||||||
|
return None
|
||||||
|
if (intf.bInterfaceSubClass == HID_SUBCLASS_BOOT
|
||||||
|
and intf.bInterfaceProtocol == HID_PROTOCOL_KEYBOARD):
|
||||||
|
return 'boot_keyboard'
|
||||||
|
if (intf.bInterfaceSubClass == HID_SUBCLASS_BOOT
|
||||||
|
and intf.bInterfaceProtocol == HID_PROTOCOL_MOUSE):
|
||||||
|
return 'boot_mouse'
|
||||||
|
# Determining any other HID dev type, like a non-boot_keyboard or
|
||||||
|
# a non-boot_mouse requires getting and parsing a HID Report descriptor
|
||||||
|
# for intf.
|
||||||
|
# Only the boot_keyboard, boot_mouse and other_device are used for this
|
||||||
|
# greentea test suite.
|
||||||
|
return 'other_device'
|
||||||
|
|
||||||
|
|
||||||
|
class RetryError(Exception):
|
||||||
|
"""Exception raised by retry_fun_call()."""
|
||||||
|
|
||||||
|
|
||||||
|
def retry_fun_call(fun, num_retries=3, retry_delay=0.0):
|
||||||
|
"""Call fun and retry if any exception was raised.
|
||||||
|
|
||||||
|
fun is called at most num_retries with a retry_dalay in between calls.
|
||||||
|
Raises RetryError if the retry limit is exhausted.
|
||||||
|
"""
|
||||||
|
verbose = False
|
||||||
|
final_err = None
|
||||||
|
for retry in range(1, num_retries + 1):
|
||||||
|
try:
|
||||||
|
return fun() # pylint: disable=not-callable
|
||||||
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
|
final_err = exc
|
||||||
|
if verbose:
|
||||||
|
print('Retry {}/{} failed ({})'
|
||||||
|
.format(retry, num_retries, str(fun)))
|
||||||
|
time.sleep(retry_delay)
|
||||||
|
err_msg = 'Failed with "{}". Tried {} times.'
|
||||||
|
raise RetryError(err_msg.format(final_err, num_retries))
|
||||||
|
|
||||||
|
|
||||||
|
def raise_if_different(expected, actual, text=''):
|
||||||
|
"""Raise a RuntimeError if actual is different than expected."""
|
||||||
|
if expected != actual:
|
||||||
|
raise RuntimeError('{}Got {!r}, expected {!r}.'.format(text, actual, expected))
|
||||||
|
|
||||||
|
|
||||||
|
def raise_if_false(expression, text):
|
||||||
|
"""Raise a RuntimeError if expression is False."""
|
||||||
|
if not expression:
|
||||||
|
raise RuntimeError(text)
|
||||||
|
|
||||||
|
|
||||||
|
class USBHIDTest(mbed_host_tests.BaseHostTest):
|
||||||
|
"""Host side test for USB device HID class."""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_usb_hid_path(usb_id_str):
|
||||||
|
"""Get a USB HID device path as registered in the system.
|
||||||
|
|
||||||
|
Search is based on the unique USB SN generated by the host
|
||||||
|
during test suite setup.
|
||||||
|
Raises RuntimeError if the device is not found.
|
||||||
|
"""
|
||||||
|
hid_path = usb_hid_path(usb_id_str)
|
||||||
|
if hid_path is None:
|
||||||
|
err_msg = 'USB HID device (SN={}) not found.'
|
||||||
|
raise RuntimeError(err_msg.format(usb_id_str))
|
||||||
|
return hid_path
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_usb_dev(usb_id_str):
|
||||||
|
"""Get a usb.core.Device instance.
|
||||||
|
|
||||||
|
Search is based on the unique USB SN generated by the host
|
||||||
|
during test suite setup.
|
||||||
|
Raises RuntimeError if the device is not found.
|
||||||
|
"""
|
||||||
|
usb_dev = usb.core.find(custom_match=lambda d: d.serial_number == usb_id_str)
|
||||||
|
if usb_dev is None:
|
||||||
|
err_msg = 'USB device (SN={}) not found.'
|
||||||
|
raise RuntimeError(err_msg.format(usb_id_str))
|
||||||
|
return usb_dev
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super(USBHIDTest, self).__init__()
|
||||||
|
self.__bg_task = None
|
||||||
|
self.dut_usb_dev_sn = uuid.uuid4().hex # 32 hex digit string
|
||||||
|
|
||||||
|
def notify_error(self, msg):
|
||||||
|
"""Terminate the test with an error msg."""
|
||||||
|
self.log('TEST ERROR: {}'.format(msg))
|
||||||
|
self.notify_complete(None)
|
||||||
|
|
||||||
|
def notify_failure(self, msg):
|
||||||
|
"""Report a host side test failure to the DUT."""
|
||||||
|
self.log('TEST FAILED: {}'.format(msg))
|
||||||
|
self.send_kv(MSG_KEY_TEST_CASE_FAILED, MSG_VALUE_DUMMY)
|
||||||
|
|
||||||
|
def notify_success(self, value=None, msg=''):
|
||||||
|
"""Report a host side test success to the DUT."""
|
||||||
|
if msg:
|
||||||
|
self.log('TEST PASSED: {}'.format(msg))
|
||||||
|
if value is None:
|
||||||
|
value = MSG_VALUE_DUMMY
|
||||||
|
self.send_kv(MSG_KEY_TEST_CASE_PASSED, value)
|
||||||
|
|
||||||
|
def cb_test_get_hid_desc(self, key, value, timestamp):
|
||||||
|
"""Verify the device handles Get_Descriptor request correctly.
|
||||||
|
|
||||||
|
Two requests are tested for every HID interface:
|
||||||
|
1. Get_Descriptor(HID),
|
||||||
|
2. Get_Descriptor(Report).
|
||||||
|
Details in USB Device Class Definition for HID, v1.11, paragraph 7.1.
|
||||||
|
"""
|
||||||
|
kwargs_hid_desc_req = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_STANDARD, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': USB_REQUEST_GET_DESCRIPTOR,
|
||||||
|
# Descriptor Index (part of wValue) is reset to zero for
|
||||||
|
# HID class descriptors other than Physical ones.
|
||||||
|
'wValue': build_get_desc_value(DESC_TYPE_HID_HID, 0x00),
|
||||||
|
# wIndex is replaced with the Interface Number in the loop.
|
||||||
|
'wIndex': None,
|
||||||
|
'data_or_wLength': DESC_LEN_HID_HID}
|
||||||
|
kwargs_report_desc_req = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_STANDARD, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': USB_REQUEST_GET_DESCRIPTOR,
|
||||||
|
# Descriptor Index (part of wValue) is reset to zero for
|
||||||
|
# HID class descriptors other than Physical ones.
|
||||||
|
'wValue': build_get_desc_value(DESC_TYPE_HID_REPORT, 0x00),
|
||||||
|
# wIndex is replaced with the Interface Number in the loop.
|
||||||
|
'wIndex': None,
|
||||||
|
# wLength is replaced with the Report Descriptor Length in the loop.
|
||||||
|
'data_or_wLength': None}
|
||||||
|
mbed_hid_dev = None
|
||||||
|
report_desc_lengths = []
|
||||||
|
try:
|
||||||
|
mbed_hid_dev = retry_fun_call(
|
||||||
|
fun=functools.partial(self.get_usb_dev, self.dut_usb_dev_sn), # pylint: disable=not-callable
|
||||||
|
num_retries=20,
|
||||||
|
retry_delay=0.05)
|
||||||
|
except RetryError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
for intf in mbed_hid_dev.get_active_configuration(): # pylint: disable=not-callable
|
||||||
|
if intf.bInterfaceClass != USB_CLASS_HID:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if mbed_hid_dev.is_kernel_driver_active(intf.bInterfaceNumber):
|
||||||
|
mbed_hid_dev.detach_kernel_driver(intf.bInterfaceNumber) # pylint: disable=not-callable
|
||||||
|
except (NotImplementedError, AttributeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Request the HID descriptor.
|
||||||
|
kwargs_hid_desc_req['wIndex'] = intf.bInterfaceNumber
|
||||||
|
hid_desc = mbed_hid_dev.ctrl_transfer(**kwargs_hid_desc_req) # pylint: disable=not-callable
|
||||||
|
try:
|
||||||
|
bNumDescriptors, bDescriptorType, wDescriptorLength = get_hid_descriptor_parts(hid_desc) # pylint: disable=invalid-name
|
||||||
|
except TypeError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
raise_if_different(1, bNumDescriptors, 'Exactly one HID Report descriptor expected. ')
|
||||||
|
raise_if_different(DESC_TYPE_HID_REPORT, bDescriptorType, 'Invalid HID class descriptor type. ')
|
||||||
|
raise_if_false(wDescriptorLength > 0, 'Invalid HID Report descriptor length. ')
|
||||||
|
|
||||||
|
# Request the Report descriptor.
|
||||||
|
kwargs_report_desc_req['wIndex'] = intf.bInterfaceNumber
|
||||||
|
kwargs_report_desc_req['data_or_wLength'] = wDescriptorLength
|
||||||
|
report_desc = mbed_hid_dev.ctrl_transfer(**kwargs_report_desc_req) # pylint: disable=not-callable
|
||||||
|
raise_if_different(wDescriptorLength, len(report_desc),
|
||||||
|
'The size of data received does not match the HID Report descriptor length. ')
|
||||||
|
report_desc_lengths.append(len(report_desc))
|
||||||
|
except usb.core.USBError as exc:
|
||||||
|
self.notify_failure('Get_Descriptor request failed. {}'.format(exc))
|
||||||
|
except RuntimeError as exc:
|
||||||
|
self.notify_failure(exc)
|
||||||
|
else:
|
||||||
|
# Send the report desc len to the device.
|
||||||
|
# USBHID::report_desc_length() returns uint16_t
|
||||||
|
msg_value = '{0:04x}'.format(max(report_desc_lengths))
|
||||||
|
self.notify_success(msg_value)
|
||||||
|
|
||||||
|
def cb_test_get_cfg_desc(self, key, value, timestamp):
|
||||||
|
"""Verify the device provides required HID descriptors.
|
||||||
|
|
||||||
|
USB Device Class Definition for HID, v1.11, paragraph 7.1:
|
||||||
|
When a Get_Descriptor(Configuration) request is issued, it
|
||||||
|
returns (...), and the HID descriptor for each interface.
|
||||||
|
"""
|
||||||
|
kwargs_cfg_desc_req = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_STANDARD, CTRL_RECIPIENT_DEVICE),
|
||||||
|
'bRequest': USB_REQUEST_GET_DESCRIPTOR,
|
||||||
|
# Descriptor Index (part of wValue) is reset to zero.
|
||||||
|
'wValue': build_get_desc_value(DESC_TYPE_CONFIG, 0x00),
|
||||||
|
# wIndex is reset to zero.
|
||||||
|
'wIndex': 0x00,
|
||||||
|
# wLength unknown, set to 1024.
|
||||||
|
'data_or_wLength': 1024}
|
||||||
|
mbed_hid_dev = None
|
||||||
|
try:
|
||||||
|
mbed_hid_dev = retry_fun_call(
|
||||||
|
fun=functools.partial(self.get_usb_dev, self.dut_usb_dev_sn), # pylint: disable=not-callable
|
||||||
|
num_retries=20,
|
||||||
|
retry_delay=0.05)
|
||||||
|
except RetryError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
# Request the Configuration descriptor.
|
||||||
|
cfg_desc = mbed_hid_dev.ctrl_transfer(**kwargs_cfg_desc_req) # pylint: disable=not-callable
|
||||||
|
raise_if_false(DESC_TYPE_HID_HID in get_descriptor_types(cfg_desc),
|
||||||
|
'No HID class descriptor in the Configuration descriptor.')
|
||||||
|
except usb.core.USBError as exc:
|
||||||
|
self.notify_failure('Get_Descriptor request failed. {}'.format(exc))
|
||||||
|
except RuntimeError as exc:
|
||||||
|
self.notify_failure(exc)
|
||||||
|
else:
|
||||||
|
self.notify_success()
|
||||||
|
|
||||||
|
def cb_test_class_requests(self, key, value, timestamp):
|
||||||
|
"""Verify all required HID requests are supported.
|
||||||
|
|
||||||
|
USB Device Class Definition for HID, v1.11, Appendix G:
|
||||||
|
1. Get_Report -- required for all types,
|
||||||
|
2. Set_Report -- not required if dev doesn't declare an Output Report,
|
||||||
|
3. Get_Idle -- required for keyboards,
|
||||||
|
4. Set_Idle -- required for keyboards,
|
||||||
|
5. Get_Protocol -- required for boot_keyboard and boot_mouse,
|
||||||
|
6. Set_Protocol -- required for boot_keyboard and boot_mouse.
|
||||||
|
|
||||||
|
Details in USB Device Class Definition for HID, v1.11, paragraph 7.2.
|
||||||
|
"""
|
||||||
|
kwargs_get_report_request = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': HID_REQUEST_GET_REPORT,
|
||||||
|
# wValue: ReportType = Input, ReportID = 0 (not used)
|
||||||
|
'wValue': (0x01 << 8) | 0x00,
|
||||||
|
# wIndex: InterfaceNumber (defined later)
|
||||||
|
'wIndex': None,
|
||||||
|
# wLength: unknown, set to 1024
|
||||||
|
'data_or_wLength': 1024}
|
||||||
|
kwargs_get_idle_request = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': HID_REQUEST_GET_IDLE,
|
||||||
|
# wValue: 0, ReportID = 0 (not used)
|
||||||
|
'wValue': (0x00 << 8) | 0x00,
|
||||||
|
# wIndex: InterfaceNumber (defined later)
|
||||||
|
'wIndex': None,
|
||||||
|
'data_or_wLength': 1}
|
||||||
|
kwargs_set_idle_request = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_OUT, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': HID_REQUEST_SET_IDLE,
|
||||||
|
# wValue: Duration, ReportID = 0 (all input reports)
|
||||||
|
'wValue': (KEYBOARD_IDLE_RATE_TO_SET << 8) | 0x00,
|
||||||
|
# wIndex: InterfaceNumber (defined later)
|
||||||
|
'wIndex': None,
|
||||||
|
'data_or_wLength': 0}
|
||||||
|
kwargs_get_protocol_request = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_IN, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': HID_REQUEST_GET_PROTOCOL,
|
||||||
|
'wValue': 0x00,
|
||||||
|
# wIndex: InterfaceNumber (defined later)
|
||||||
|
'wIndex': None,
|
||||||
|
'data_or_wLength': 1}
|
||||||
|
kwargs_set_protocol_request = {
|
||||||
|
'bmRequestType': build_request_type(
|
||||||
|
CTRL_OUT, CTRL_TYPE_CLASS, CTRL_RECIPIENT_INTERFACE),
|
||||||
|
'bRequest': HID_REQUEST_SET_PROTOCOL,
|
||||||
|
'wValue': HID_PROTOCOL_TO_SET,
|
||||||
|
# wIndex: InterfaceNumber (defined later)
|
||||||
|
'wIndex': None,
|
||||||
|
'data_or_wLength': 0}
|
||||||
|
mbed_hid_dev = None
|
||||||
|
try:
|
||||||
|
mbed_hid_dev = retry_fun_call(
|
||||||
|
fun=functools.partial(self.get_usb_dev, self.dut_usb_dev_sn), # pylint: disable=not-callable
|
||||||
|
num_retries=20,
|
||||||
|
retry_delay=0.05)
|
||||||
|
except RetryError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
hid_dev_type = None
|
||||||
|
tested_request_name = None
|
||||||
|
try:
|
||||||
|
for intf in mbed_hid_dev.get_active_configuration(): # pylint: disable=not-callable
|
||||||
|
hid_dev_type = get_usbhid_dev_type(intf)
|
||||||
|
if hid_dev_type is None:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
if mbed_hid_dev.is_kernel_driver_active(intf.bInterfaceNumber):
|
||||||
|
mbed_hid_dev.detach_kernel_driver(intf.bInterfaceNumber) # pylint: disable=not-callable
|
||||||
|
except (NotImplementedError, AttributeError):
|
||||||
|
pass
|
||||||
|
if hid_dev_type == 'boot_keyboard':
|
||||||
|
# 4. Set_Idle
|
||||||
|
tested_request_name = 'Set_Idle'
|
||||||
|
kwargs_set_idle_request['wIndex'] = intf.bInterfaceNumber
|
||||||
|
mbed_hid_dev.ctrl_transfer(**kwargs_set_idle_request) # pylint: disable=not-callable
|
||||||
|
# 3. Get_Idle
|
||||||
|
tested_request_name = 'Get_Idle'
|
||||||
|
kwargs_get_idle_request['wIndex'] = intf.bInterfaceNumber
|
||||||
|
idle_rate = mbed_hid_dev.ctrl_transfer(**kwargs_get_idle_request) # pylint: disable=not-callable
|
||||||
|
raise_if_different(KEYBOARD_IDLE_RATE_TO_SET, idle_rate, 'Invalid idle rate received. ')
|
||||||
|
if hid_dev_type in ('boot_keyboard', 'boot_mouse'):
|
||||||
|
# 6. Set_Protocol
|
||||||
|
tested_request_name = 'Set_Protocol'
|
||||||
|
kwargs_set_protocol_request['wIndex'] = intf.bInterfaceNumber
|
||||||
|
mbed_hid_dev.ctrl_transfer(**kwargs_set_protocol_request) # pylint: disable=not-callable
|
||||||
|
# 5. Get_Protocol
|
||||||
|
tested_request_name = 'Get_Protocol'
|
||||||
|
kwargs_get_protocol_request['wIndex'] = intf.bInterfaceNumber
|
||||||
|
protocol = mbed_hid_dev.ctrl_transfer(**kwargs_get_protocol_request) # pylint: disable=not-callable
|
||||||
|
raise_if_different(HID_PROTOCOL_TO_SET, protocol, 'Invalid protocol received. ')
|
||||||
|
# 1. Get_Report
|
||||||
|
tested_request_name = 'Get_Report'
|
||||||
|
kwargs_get_report_request['wIndex'] = intf.bInterfaceNumber
|
||||||
|
mbed_hid_dev.ctrl_transfer(**kwargs_get_report_request) # pylint: disable=not-callable
|
||||||
|
except usb.core.USBError as exc:
|
||||||
|
self.notify_failure('The {!r} does not support the {!r} HID class request ({}).'
|
||||||
|
.format(hid_dev_type, tested_request_name, exc))
|
||||||
|
except RuntimeError as exc:
|
||||||
|
self.notify_failure('Set/Get data mismatch for {!r} for the {!r} HID class request ({}).'
|
||||||
|
.format(hid_dev_type, tested_request_name, exc))
|
||||||
|
else:
|
||||||
|
self.notify_success()
|
||||||
|
|
||||||
|
def raw_loopback(self, report_size):
|
||||||
|
"""Send every input report back to the device."""
|
||||||
|
mbed_hid_path = None
|
||||||
|
mbed_hid = hid.device()
|
||||||
|
try:
|
||||||
|
mbed_hid_path = retry_fun_call(
|
||||||
|
fun=functools.partial(self.get_usb_hid_path, self.dut_usb_dev_sn), # pylint: disable=not-callable
|
||||||
|
num_retries=20,
|
||||||
|
retry_delay=0.05)
|
||||||
|
retry_fun_call(
|
||||||
|
fun=functools.partial(mbed_hid.open_path, mbed_hid_path), # pylint: disable=not-callable
|
||||||
|
num_retries=10,
|
||||||
|
retry_delay=0.05)
|
||||||
|
except RetryError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
# Notify the device it can send reports now.
|
||||||
|
self.send_kv(MSG_KEY_HOST_READY, MSG_VALUE_DUMMY)
|
||||||
|
try:
|
||||||
|
for _ in range(RAW_IO_REPS):
|
||||||
|
# There are no Report ID tags in the Report descriptor.
|
||||||
|
# Receiving only the Report Data, Report ID is omitted.
|
||||||
|
report_in = mbed_hid.read(report_size)
|
||||||
|
report_out = report_in[:]
|
||||||
|
# Set the Report ID to 0x00 (not used).
|
||||||
|
report_out.insert(0, 0x00)
|
||||||
|
mbed_hid.write(report_out)
|
||||||
|
except (ValueError, IOError) as exc:
|
||||||
|
self.notify_failure('HID Report transfer failed. {}'.format(exc))
|
||||||
|
finally:
|
||||||
|
mbed_hid.close()
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
self.register_callback(MSG_KEY_DEVICE_READY, self.cb_device_ready)
|
||||||
|
self.register_callback(MSG_KEY_TEST_GET_DESCRIPTOR_HID, self.cb_test_get_hid_desc)
|
||||||
|
self.register_callback(MSG_KEY_TEST_GET_DESCRIPTOR_CFG, self.cb_test_get_cfg_desc)
|
||||||
|
self.register_callback(MSG_KEY_TEST_REQUESTS, self.cb_test_class_requests)
|
||||||
|
self.register_callback(MSG_KEY_TEST_RAW_IO, self.cb_test_raw_io)
|
||||||
|
|
||||||
|
def cb_device_ready(self, key, value, timestamp):
|
||||||
|
"""Send a unique USB SN to the device.
|
||||||
|
|
||||||
|
DUT uses this SN every time it connects to host as a USB device.
|
||||||
|
"""
|
||||||
|
self.send_kv(MSG_KEY_SERIAL_NUMBER, self.dut_usb_dev_sn)
|
||||||
|
|
||||||
|
def start_bg_task(self, **thread_kwargs):
|
||||||
|
"""Start a new daemon thread.
|
||||||
|
|
||||||
|
Some callbacks delegate HID dev handling to a background task to
|
||||||
|
prevent any delays in the device side assert handling. Only one
|
||||||
|
background task is kept running to prevent multiple access
|
||||||
|
to the HID device.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
self.__bg_task.join()
|
||||||
|
except (AttributeError, RuntimeError):
|
||||||
|
pass
|
||||||
|
self.__bg_task = threading.Thread(**thread_kwargs)
|
||||||
|
self.__bg_task.daemon = True
|
||||||
|
self.__bg_task.start()
|
||||||
|
|
||||||
|
def cb_test_raw_io(self, key, value, timestamp):
|
||||||
|
"""Receive HID reports and send them back to the device."""
|
||||||
|
if not CYTHON_HIDAPI_PRESENT:
|
||||||
|
self.send_kv(MSG_KEY_HOST_READY, MSG_VALUE_NOT_SUPPORTED)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
# The size of input and output reports used in test.
|
||||||
|
report_size = int(value)
|
||||||
|
except ValueError as exc:
|
||||||
|
self.notify_error(exc)
|
||||||
|
return
|
||||||
|
self.start_bg_task(
|
||||||
|
target=self.raw_loopback,
|
||||||
|
args=(report_size, ))
|
|
@ -74,9 +74,10 @@ Case cases[] = {
|
||||||
Case("1 s delay during deepsleep (attach_us)", test_deepsleep<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
|
Case("1 s delay during deepsleep (attach_us)", test_deepsleep<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
|
||||||
greentea_failure_handler),
|
greentea_failure_handler),
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(__ARM_FM) //FastModels not support time drifting test
|
||||||
Case("Timing drift (attach)", test_drift<AttachTester<LowPowerTimeout> >),
|
Case("Timing drift (attach)", test_drift<AttachTester<LowPowerTimeout> >),
|
||||||
Case("Timing drift (attach_us)", test_drift<AttachUSTester<LowPowerTimeout> >),
|
Case("Timing drift (attach_us)", test_drift<AttachUSTester<LowPowerTimeout> >),
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
|
|
|
@ -859,9 +859,6 @@ Within each loop, one `recvfrom()` may return the received packet size
|
||||||
When `NSAPI_ERROR_WOULD_BLOCK` is received, check that time consumed is
|
When `NSAPI_ERROR_WOULD_BLOCK` is received, check that time consumed is
|
||||||
more that 100 milliseconds but less than 200 milliseconds.
|
more that 100 milliseconds but less than 200 milliseconds.
|
||||||
|
|
||||||
After repeating for 10 times, at least 5 packets must have been
|
|
||||||
received.
|
|
||||||
|
|
||||||
|
|
||||||
### UDPSOCKET_SENDTO_TIMEOUT
|
### UDPSOCKET_SENDTO_TIMEOUT
|
||||||
|
|
||||||
|
|
|
@ -67,16 +67,16 @@ void TCPSOCKET_ECHOTEST()
|
||||||
|
|
||||||
int recvd;
|
int recvd;
|
||||||
int sent;
|
int sent;
|
||||||
int x = 0;
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); s_idx++) {
|
||||||
for (int pkt_s = pkt_sizes[x]; x < PKTS; pkt_s = pkt_sizes[x++]) {
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
fill_tx_buffer_ascii(tcp_global::tx_buffer, BUFF_SIZE);
|
fill_tx_buffer_ascii(tcp_global::tx_buffer, BUFF_SIZE);
|
||||||
sent = sock.send(tcp_global::tx_buffer, pkt_s);
|
sent = sock.send(tcp_global::tx_buffer, pkt_s);
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
printf("[Round#%02d] network error %d\n", x, sent);
|
printf("[Round#%02d] network error %d\n", s_idx, sent);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
break;
|
break;
|
||||||
} else if (sent != pkt_s) {
|
} else if (sent != pkt_s) {
|
||||||
printf("[%02d] sock.send return size %d does not match the expectation %d\n", x, sent, pkt_s);
|
printf("[%02d] sock.send return size %d does not match the expectation %d\n", s_idx, sent, pkt_s);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ void TCPSOCKET_ECHOTEST()
|
||||||
while (bytes2recv) {
|
while (bytes2recv) {
|
||||||
recvd = sock.recv(&(tcp_global::rx_buffer[sent - bytes2recv]), bytes2recv);
|
recvd = sock.recv(&(tcp_global::rx_buffer[sent - bytes2recv]), bytes2recv);
|
||||||
if (recvd < 0) {
|
if (recvd < 0) {
|
||||||
printf("[Round#%02d] network error %d\n", x, recvd);
|
printf("[Round#%02d] network error %d\n", s_idx, recvd);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
||||||
return;
|
return;
|
||||||
|
@ -143,7 +143,6 @@ void TCPSOCKET_ECHOTEST_NONBLOCK()
|
||||||
|
|
||||||
int bytes2send;
|
int bytes2send;
|
||||||
int sent;
|
int sent;
|
||||||
int s_idx = 0;
|
|
||||||
receive_error = false;
|
receive_error = false;
|
||||||
unsigned char *stack_mem = (unsigned char *)malloc(tcp_global::TCP_OS_STACK_SIZE);
|
unsigned char *stack_mem = (unsigned char *)malloc(tcp_global::TCP_OS_STACK_SIZE);
|
||||||
TEST_ASSERT_NOT_NULL(stack_mem);
|
TEST_ASSERT_NOT_NULL(stack_mem);
|
||||||
|
@ -154,8 +153,8 @@ void TCPSOCKET_ECHOTEST_NONBLOCK()
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(osOK, receiver_thread->start(callback(&queue, &EventQueue::dispatch_forever)));
|
TEST_ASSERT_EQUAL(osOK, receiver_thread->start(callback(&queue, &EventQueue::dispatch_forever)));
|
||||||
|
|
||||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; ++s_idx) {
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) {
|
||||||
pkt_s = pkt_sizes[s_idx];
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
bytes2recv = pkt_s;
|
bytes2recv = pkt_s;
|
||||||
bytes2recv_total = pkt_s;
|
bytes2recv_total = pkt_s;
|
||||||
|
|
||||||
|
|
|
@ -70,17 +70,17 @@ void TLSSOCKET_ECHOTEST()
|
||||||
|
|
||||||
int recvd;
|
int recvd;
|
||||||
int sent;
|
int sent;
|
||||||
int x = 0;
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); s_idx++) {
|
||||||
for (int pkt_s = pkt_sizes[x]; x < PKTS; pkt_s = pkt_sizes[x++]) {
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
fill_tx_buffer_ascii(tls_global::tx_buffer, BUFF_SIZE);
|
fill_tx_buffer_ascii(tls_global::tx_buffer, BUFF_SIZE);
|
||||||
|
|
||||||
sent = sock->send(tls_global::tx_buffer, pkt_s);
|
sent = sock->send(tls_global::tx_buffer, pkt_s);
|
||||||
if (sent < 0) {
|
if (sent < 0) {
|
||||||
printf("[Round#%02d] network error %d\n", x, sent);
|
printf("[Round#%02d] network error %d\n", s_idx, sent);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
break;
|
break;
|
||||||
} else if (sent != pkt_s) {
|
} else if (sent != pkt_s) {
|
||||||
printf("[%02d] sock.send return size %d does not match the expectation %d\n", x, sent, pkt_s);
|
printf("[%02d] sock.send return size %d does not match the expectation %d\n", s_idx, sent, pkt_s);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -89,7 +89,7 @@ void TLSSOCKET_ECHOTEST()
|
||||||
while (bytes2recv) {
|
while (bytes2recv) {
|
||||||
recvd = sock->recv(&(tls_global::rx_buffer[sent - bytes2recv]), bytes2recv);
|
recvd = sock->recv(&(tls_global::rx_buffer[sent - bytes2recv]), bytes2recv);
|
||||||
if (recvd < 0) {
|
if (recvd < 0) {
|
||||||
printf("[Round#%02d] network error %d\n", x, recvd);
|
printf("[Round#%02d] network error %d\n", s_idx, recvd);
|
||||||
TEST_FAIL();
|
TEST_FAIL();
|
||||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close());
|
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close());
|
||||||
return;
|
return;
|
||||||
|
@ -146,7 +146,7 @@ void TLSSOCKET_ECHOTEST_NONBLOCK()
|
||||||
|
|
||||||
int bytes2send;
|
int bytes2send;
|
||||||
int sent;
|
int sent;
|
||||||
int s_idx = 0;
|
;
|
||||||
receive_error = false;
|
receive_error = false;
|
||||||
unsigned char *stack_mem = (unsigned char *)malloc(tls_global::TLS_OS_STACK_SIZE);
|
unsigned char *stack_mem = (unsigned char *)malloc(tls_global::TLS_OS_STACK_SIZE);
|
||||||
TEST_ASSERT_NOT_NULL(stack_mem);
|
TEST_ASSERT_NOT_NULL(stack_mem);
|
||||||
|
@ -158,8 +158,8 @@ void TLSSOCKET_ECHOTEST_NONBLOCK()
|
||||||
event_queue = &queue;
|
event_queue = &queue;
|
||||||
TEST_ASSERT_EQUAL(osOK, receiver_thread->start(callback(&queue, &EventQueue::dispatch_forever)));
|
TEST_ASSERT_EQUAL(osOK, receiver_thread->start(callback(&queue, &EventQueue::dispatch_forever)));
|
||||||
|
|
||||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; ++s_idx) {
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) {
|
||||||
pkt_s = pkt_sizes[s_idx];
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
bytes2recv = pkt_s;
|
bytes2recv = pkt_s;
|
||||||
bytes2recv_total = pkt_s;
|
bytes2recv_total = pkt_s;
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ using namespace utest::v1;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
static const int SIGNAL_SIGIO = 0x1;
|
static const int SIGNAL_SIGIO = 0x1;
|
||||||
static const int SIGIO_TIMEOUT = 20000; //[ms]
|
static const int SIGIO_TIMEOUT = 50000; //[ms]
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sigio_handler(osThreadId id)
|
static void _sigio_handler(osThreadId id)
|
||||||
|
|
|
@ -68,11 +68,10 @@ void UDPSOCKET_ECHOTEST()
|
||||||
|
|
||||||
int recvd;
|
int recvd;
|
||||||
int sent;
|
int sent;
|
||||||
int s_idx = 0;
|
|
||||||
int packets_sent = 0;
|
int packets_sent = 0;
|
||||||
int packets_recv = 0;
|
int packets_recv = 0;
|
||||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; pkt_s = ++s_idx) {
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) {
|
||||||
pkt_s = pkt_sizes[s_idx];
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
|
|
||||||
fill_tx_buffer_ascii(tx_buffer, BUFF_SIZE);
|
fill_tx_buffer_ascii(tx_buffer, BUFF_SIZE);
|
||||||
|
|
||||||
|
@ -147,15 +146,14 @@ void UDPSOCKET_ECHOTEST_NONBLOCK()
|
||||||
sock.sigio(callback(_sigio_handler));
|
sock.sigio(callback(_sigio_handler));
|
||||||
|
|
||||||
int sent;
|
int sent;
|
||||||
int s_idx = 0;
|
|
||||||
int packets_sent = 0;
|
int packets_sent = 0;
|
||||||
int packets_recv = 0;
|
int packets_recv = 0;
|
||||||
Thread *thread;
|
Thread *thread;
|
||||||
unsigned char *stack_mem = (unsigned char *)malloc(OS_STACK_SIZE);
|
unsigned char *stack_mem = (unsigned char *)malloc(OS_STACK_SIZE);
|
||||||
TEST_ASSERT_NOT_NULL(stack_mem);
|
TEST_ASSERT_NOT_NULL(stack_mem);
|
||||||
|
|
||||||
for (int pkt_s = pkt_sizes[s_idx]; s_idx < PKTS; ++s_idx) {
|
for (int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) {
|
||||||
pkt_s = pkt_sizes[s_idx];
|
int pkt_s = pkt_sizes[s_idx];
|
||||||
|
|
||||||
thread = new Thread(osPriorityNormal,
|
thread = new Thread(osPriorityNormal,
|
||||||
OS_STACK_SIZE,
|
OS_STACK_SIZE,
|
||||||
|
|
|
@ -27,6 +27,7 @@ using namespace utest::v1;
|
||||||
namespace {
|
namespace {
|
||||||
static const int SIGNAL_SIGIO = 0x1;
|
static const int SIGNAL_SIGIO = 0x1;
|
||||||
static const int SIGIO_TIMEOUT = 5000; //[ms]
|
static const int SIGIO_TIMEOUT = 5000; //[ms]
|
||||||
|
static const int PKT_NUM = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _sigio_handler(osThreadId id)
|
static void _sigio_handler(osThreadId id)
|
||||||
|
@ -52,7 +53,7 @@ void UDPSOCKET_RECV_TIMEOUT()
|
||||||
Timer timer;
|
Timer timer;
|
||||||
SocketAddress temp_addr;
|
SocketAddress temp_addr;
|
||||||
int pkt_success = 0;
|
int pkt_success = 0;
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < PKT_NUM; i++) {
|
||||||
TEST_ASSERT_EQUAL(DATA_LEN, sock.sendto(udp_addr, buff, DATA_LEN));
|
TEST_ASSERT_EQUAL(DATA_LEN, sock.sendto(udp_addr, buff, DATA_LEN));
|
||||||
timer.reset();
|
timer.reset();
|
||||||
timer.start();
|
timer.start();
|
||||||
|
@ -75,6 +76,6 @@ void UDPSOCKET_RECV_TIMEOUT()
|
||||||
pkt_success++;
|
pkt_success++;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_ASSERT(pkt_success >= 5);
|
printf("MBED: %d out of %d packets were received.\n", pkt_success, PKT_NUM);
|
||||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close());
|
||||||
}
|
}
|
||||||
|
|
|
@ -87,10 +87,12 @@ git checkout master
|
||||||
cd ..
|
cd ..
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Prepare an `mbed_app.json` configuration file with all the required definitions provided. See [template_mbed_app.txt](template_mbed_app.txt) file for the full list of necessary definitions.
|
||||||
|
|
||||||
Now build test binaries:
|
Now build test binaries:
|
||||||
|
|
||||||
```.sh
|
```.sh
|
||||||
mbed test --compile -t <toolchain> -m <target> -n mbed-os-tests-network-wifi
|
mbed test --compile -t <toolchain> -m <target> --app-config TESTS/network/wifi/template_mbed_app.txt -n mbed-os-tests-network-wifi
|
||||||
```
|
```
|
||||||
|
|
||||||
Running tests
|
Running tests
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
#include "psa_manifest/sid.h"
|
#include "psa_manifest/sid.h"
|
||||||
|
|
||||||
#if defined(TARGET_TFM)
|
#if defined(TARGET_TFM)
|
||||||
#include "psa/service.h"
|
|
||||||
#define MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS TFM_CONN_HANDLE_MAX_NUM
|
#define MBED_CONF_SPM_IPC_MAX_NUM_OF_CHANNELS TFM_CONN_HANDLE_MAX_NUM
|
||||||
|
#define PSA_MAX_IOVEC 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
#include "psa_manifest/sid.h"
|
#include "psa_manifest/sid.h"
|
||||||
|
|
||||||
#if defined(TARGET_TFM)
|
#if defined(TARGET_TFM)
|
||||||
#include "psa/service.h"
|
#define PSA_MAX_IOVEC 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
|
@ -29,7 +29,7 @@
|
||||||
#include "psa_manifest/sid.h"
|
#include "psa_manifest/sid.h"
|
||||||
|
|
||||||
#if defined(TARGET_TFM)
|
#if defined(TARGET_TFM)
|
||||||
#include "psa/service.h"
|
#define PSA_MAX_IOVEC 4
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Testing the USB HID device with a Linux host
|
||||||
|
|
||||||
|
Before running `tests-usb_device-hid` test suite on a Linux machine, please
|
||||||
|
make sure to install the `hidapi` Python module first, otherwise some test
|
||||||
|
cases will be skipped. Due to external dependencies for Linux, this module
|
||||||
|
is not installed during the initial setup, to keep the process as simple
|
||||||
|
as possible.
|
||||||
|
|
||||||
|
For Debian-based Linux distros, the dependencies can be installed as follows
|
||||||
|
(based on module's [README][1]):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt-get install python-dev libusb-1.0-0-dev libudev-dev
|
||||||
|
pip install --upgrade setuptools
|
||||||
|
```
|
||||||
|
To install the `hidapi` module itself, please use the attached
|
||||||
|
`TESTS/usb_device/hid/requirements.txt` file:
|
||||||
|
```bash
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
[1]: https://github.com/trezor/cython-hidapi/blob/master/README.rst#install
|
||||||
|
|
|
@ -0,0 +1,384 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018, ARM Limited, All Rights Reserved
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#if !defined(DEVICE_USBDEVICE) || !DEVICE_USBDEVICE
|
||||||
|
#error [NOT_SUPPORTED] USB Device not supported for this target
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "usb_phy_api.h"
|
||||||
|
#include "USBHID.h"
|
||||||
|
#include "USBMouse.h"
|
||||||
|
#include "USBKeyboard.h"
|
||||||
|
|
||||||
|
// Reuse the VID & PID from basic USB test.
|
||||||
|
#define USB_HID_VID 0x0d28
|
||||||
|
#define USB_HID_PID_GENERIC 0x0206
|
||||||
|
#define USB_HID_PID_KEYBOARD 0x0206
|
||||||
|
#define USB_HID_PID_MOUSE 0x0206
|
||||||
|
#define USB_HID_PID_GENERIC2 0x0007
|
||||||
|
|
||||||
|
#define MSG_VALUE_LEN 24
|
||||||
|
#define MSG_KEY_LEN 24
|
||||||
|
#define MSG_KEY_DEVICE_READY "ready"
|
||||||
|
#define MSG_KEY_DEVICE_READY "dev_ready"
|
||||||
|
#define MSG_KEY_HOST_READY "host_ready"
|
||||||
|
#define MSG_KEY_SERIAL_NUMBER "usb_dev_sn"
|
||||||
|
#define MSG_KEY_TEST_GET_DESCRIPTOR_HID "test_get_desc_hid"
|
||||||
|
#define MSG_KEY_TEST_GET_DESCRIPTOR_CFG "test_get_desc_cfg"
|
||||||
|
#define MSG_KEY_TEST_REQUESTS "test_requests"
|
||||||
|
#define MSG_KEY_TEST_RAW_IO "test_raw_io"
|
||||||
|
|
||||||
|
#define MSG_KEY_TEST_CASE_FAILED "fail"
|
||||||
|
#define MSG_KEY_TEST_CASE_PASSED "pass"
|
||||||
|
#define MSG_VALUE_DUMMY "0"
|
||||||
|
#define MSG_VALUE_NOT_SUPPORTED "not_supported"
|
||||||
|
|
||||||
|
#define RAW_IO_REPS 16
|
||||||
|
|
||||||
|
#define USB_DEV_SN_LEN (32) // 32 hex digit UUID
|
||||||
|
#define NONASCII_CHAR ('?')
|
||||||
|
#define USB_DEV_SN_DESC_SIZE (USB_DEV_SN_LEN * 2 + 2)
|
||||||
|
|
||||||
|
const char *default_serial_num = "0123456789";
|
||||||
|
char usb_dev_sn[USB_DEV_SN_LEN + 1];
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
using utest::v1::Specification;
|
||||||
|
using utest::v1::Harness;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a USB string descriptor to C style ASCII
|
||||||
|
*
|
||||||
|
* The string placed in str is always null-terminated which may cause the
|
||||||
|
* loss of data if n is to small. If the length of descriptor string is less
|
||||||
|
* than n, additional null bytes are written to str.
|
||||||
|
*
|
||||||
|
* @param str output buffer for the ASCII string
|
||||||
|
* @param usb_desc USB string descriptor
|
||||||
|
* @param n size of str buffer
|
||||||
|
* @returns number of non-null bytes returned in str or -1 on failure
|
||||||
|
*/
|
||||||
|
int usb_string_desc2ascii(char *str, const uint8_t *usb_desc, size_t n)
|
||||||
|
{
|
||||||
|
if (str == NULL || usb_desc == NULL || n < 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// bDescriptorType @ offset 1
|
||||||
|
if (usb_desc[1] != STRING_DESCRIPTOR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// bLength @ offset 0
|
||||||
|
const size_t bLength = usb_desc[0];
|
||||||
|
if (bLength % 2 != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t s, d;
|
||||||
|
for (s = 0, d = 2; s < n - 1 && d < bLength; s++, d += 2) {
|
||||||
|
// handle non-ASCII characters
|
||||||
|
if (usb_desc[d] > 0x7f || usb_desc[d + 1] != 0) {
|
||||||
|
str[s] = NONASCII_CHAR;
|
||||||
|
} else {
|
||||||
|
str[s] = usb_desc[d];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int str_len = s;
|
||||||
|
for (; s < n; s++) {
|
||||||
|
str[s] = '\0';
|
||||||
|
}
|
||||||
|
return str_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a C style ASCII to a USB string descriptor
|
||||||
|
*
|
||||||
|
* @param usb_desc output buffer for the USB string descriptor
|
||||||
|
* @param str ASCII string
|
||||||
|
* @param n size of usb_desc buffer, even number
|
||||||
|
* @returns number of bytes returned in usb_desc or -1 on failure
|
||||||
|
*/
|
||||||
|
int ascii2usb_string_desc(uint8_t *usb_desc, const char *str, size_t n)
|
||||||
|
{
|
||||||
|
if (str == NULL || usb_desc == NULL || n < 4) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (n % 2 != 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
size_t s, d;
|
||||||
|
// set bString (@ offset 2 onwards) as a UNICODE UTF-16LE string
|
||||||
|
memset(usb_desc, 0, n);
|
||||||
|
for (s = 0, d = 2; str[s] != '\0' && d < n; s++, d += 2) {
|
||||||
|
usb_desc[d] = str[s];
|
||||||
|
}
|
||||||
|
// set bLength @ offset 0
|
||||||
|
usb_desc[0] = d;
|
||||||
|
// set bDescriptorType @ offset 1
|
||||||
|
usb_desc[1] = STRING_DESCRIPTOR;
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestUSBHID: public USBHID {
|
||||||
|
private:
|
||||||
|
uint8_t _serial_num_descriptor[USB_DEV_SN_DESC_SIZE];
|
||||||
|
public:
|
||||||
|
TestUSBHID(uint16_t vendor_id, uint16_t product_id, const char *serial_number = default_serial_num, uint8_t output_report_length = 64, uint8_t input_report_length = 64) :
|
||||||
|
USBHID(get_usb_phy(), output_report_length, input_report_length, vendor_id, product_id, 0x01)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
int rc = ascii2usb_string_desc(_serial_num_descriptor, serial_number, USB_DEV_SN_DESC_SIZE);
|
||||||
|
if (rc < 0) {
|
||||||
|
ascii2usb_string_desc(_serial_num_descriptor, default_serial_num, USB_DEV_SN_DESC_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TestUSBHID()
|
||||||
|
{
|
||||||
|
deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const uint8_t *string_iserial_desc()
|
||||||
|
{
|
||||||
|
return (const uint8_t *) _serial_num_descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this accessible for tests (public).
|
||||||
|
using USBHID::report_desc_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestUSBMouse: public USBMouse {
|
||||||
|
private:
|
||||||
|
uint8_t _serial_num_descriptor[USB_DEV_SN_DESC_SIZE];
|
||||||
|
public:
|
||||||
|
TestUSBMouse(uint16_t vendor_id, uint16_t product_id, const char *serial_number = default_serial_num) :
|
||||||
|
USBMouse(get_usb_phy(), REL_MOUSE, vendor_id, product_id, 0x01)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
int rc = ascii2usb_string_desc(_serial_num_descriptor, serial_number, USB_DEV_SN_DESC_SIZE);
|
||||||
|
if (rc < 0) {
|
||||||
|
ascii2usb_string_desc(_serial_num_descriptor, default_serial_num, USB_DEV_SN_DESC_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TestUSBMouse()
|
||||||
|
{
|
||||||
|
deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const uint8_t *string_iserial_desc()
|
||||||
|
{
|
||||||
|
return (const uint8_t *) _serial_num_descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this accessible for tests (public).
|
||||||
|
using USBHID::report_desc_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestUSBKeyboard: public USBKeyboard {
|
||||||
|
private:
|
||||||
|
uint8_t _serial_num_descriptor[USB_DEV_SN_DESC_SIZE];
|
||||||
|
public:
|
||||||
|
TestUSBKeyboard(uint16_t vendor_id, uint16_t product_id, const char *serial_number = default_serial_num) :
|
||||||
|
USBKeyboard(get_usb_phy(), vendor_id, product_id, 0x01)
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
int rc = ascii2usb_string_desc(_serial_num_descriptor, serial_number, USB_DEV_SN_DESC_SIZE);
|
||||||
|
if (rc < 0) {
|
||||||
|
ascii2usb_string_desc(_serial_num_descriptor, default_serial_num, USB_DEV_SN_DESC_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~TestUSBKeyboard()
|
||||||
|
{
|
||||||
|
deinit();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const uint8_t *string_iserial_desc()
|
||||||
|
{
|
||||||
|
return (const uint8_t *) _serial_num_descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make this accessible for tests (public).
|
||||||
|
using USBHID::report_desc_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Test Get_Descriptor request with the HID class descriptors
|
||||||
|
*
|
||||||
|
* Given a USB HID class device connected to a host,
|
||||||
|
* when the host issues the Get_Descriptor(HID) request,
|
||||||
|
* then the device returns the HID descriptor.
|
||||||
|
*
|
||||||
|
* When the host issues the Get_Descriptor(Report) request,
|
||||||
|
* then the device returns the Report descriptor
|
||||||
|
* and the size of the descriptor is equal to USBHID::report_desc_length().
|
||||||
|
*
|
||||||
|
* Details in USB Device Class Definition for HID, v1.11, paragraph 7.1.
|
||||||
|
*/
|
||||||
|
template<typename T, uint16_t PID>
|
||||||
|
void test_get_hid_class_desc()
|
||||||
|
{
|
||||||
|
T usb_hid(USB_HID_VID, PID, usb_dev_sn);
|
||||||
|
usb_hid.connect();
|
||||||
|
greentea_send_kv(MSG_KEY_TEST_GET_DESCRIPTOR_HID, MSG_VALUE_DUMMY);
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MSG_KEY_TEST_CASE_PASSED, key);
|
||||||
|
uint16_t host_report_desc_len;
|
||||||
|
int num_args = sscanf(value, "%04hx", &host_report_desc_len);
|
||||||
|
TEST_ASSERT_MESSAGE(num_args != 0 && num_args != EOF, "Invalid data received from host.");
|
||||||
|
TEST_ASSERT_EQUAL_UINT16(usb_hid.report_desc_length(), host_report_desc_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test Get_Descriptor request with the Configuration descriptor
|
||||||
|
*
|
||||||
|
* Given a USB HID class device connected to a host,
|
||||||
|
* when the host issues the Get_Descriptor(Configuration) request,
|
||||||
|
* then the device returns the Configuration descriptor and a HID
|
||||||
|
* descriptor for each HID interface.
|
||||||
|
*
|
||||||
|
* Details in USB Device Class Definition for HID, v1.11, paragraph 7.1.
|
||||||
|
*/
|
||||||
|
template<typename T, uint16_t PID>
|
||||||
|
void test_get_configuration_desc()
|
||||||
|
{
|
||||||
|
T usb_hid(USB_HID_VID, PID, usb_dev_sn);
|
||||||
|
usb_hid.connect();
|
||||||
|
greentea_send_kv(MSG_KEY_TEST_GET_DESCRIPTOR_CFG, MSG_VALUE_DUMMY);
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MSG_KEY_TEST_CASE_PASSED, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test HID class requests
|
||||||
|
*
|
||||||
|
* Given a USB HID class device connected to a host,
|
||||||
|
* when the host issues a request specific to the HID class device type,
|
||||||
|
* then the device returns valid data.
|
||||||
|
*
|
||||||
|
* Details in USB Device Class Definition for HID, v1.11,
|
||||||
|
* paragraph 7.2 and Appendix G.
|
||||||
|
*/
|
||||||
|
template<typename T, uint16_t PID>
|
||||||
|
void test_class_requests()
|
||||||
|
{
|
||||||
|
T usb_hid(USB_HID_VID, PID, usb_dev_sn);
|
||||||
|
usb_hid.connect();
|
||||||
|
greentea_send_kv(MSG_KEY_TEST_REQUESTS, MSG_VALUE_DUMMY);
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MSG_KEY_TEST_CASE_PASSED, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test send & read
|
||||||
|
*
|
||||||
|
* Given a USB HID class device connected to a host,
|
||||||
|
* when the device sends input reports with a random data to the host
|
||||||
|
* and the host sends them back to the device,
|
||||||
|
* then received output report data is equal to the input report data.
|
||||||
|
*/
|
||||||
|
template<uint8_t REPORT_SIZE> // Range [1, MAX_HID_REPORT_SIZE].
|
||||||
|
void test_generic_raw_io()
|
||||||
|
{
|
||||||
|
TestUSBHID usb_hid(USB_HID_VID, USB_HID_PID_GENERIC2, usb_dev_sn, REPORT_SIZE, REPORT_SIZE);
|
||||||
|
usb_hid.connect();
|
||||||
|
greentea_send_kv(MSG_KEY_TEST_RAW_IO, REPORT_SIZE);
|
||||||
|
|
||||||
|
// Wait for the host HID driver to complete setup.
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char value[MSG_VALUE_LEN + 1] = { };
|
||||||
|
greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN);
|
||||||
|
TEST_ASSERT_EQUAL_STRING(MSG_KEY_HOST_READY, key);
|
||||||
|
if (strcmp(value, MSG_VALUE_NOT_SUPPORTED) == 0) {
|
||||||
|
TEST_IGNORE_MESSAGE("Test case not supported by host plarform.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Report ID omitted here. There are no Report ID tags in the Report descriptor.
|
||||||
|
HID_REPORT input_report = {};
|
||||||
|
HID_REPORT output_report = {};
|
||||||
|
for (size_t r = 0; r < RAW_IO_REPS; r++) {
|
||||||
|
for (size_t i = 0; i < REPORT_SIZE; i++) {
|
||||||
|
input_report.data[i] = (uint8_t)(rand() % 0x100);
|
||||||
|
}
|
||||||
|
input_report.length = REPORT_SIZE;
|
||||||
|
output_report.length = 0;
|
||||||
|
TEST_ASSERT(usb_hid.send(&input_report));
|
||||||
|
TEST_ASSERT(usb_hid.read(&output_report));
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(input_report.length, output_report.length);
|
||||||
|
TEST_ASSERT_EQUAL_UINT8_ARRAY(input_report.data, output_report.data, REPORT_SIZE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t testsuite_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(45, "usb_device_hid");
|
||||||
|
srand((unsigned) ticker_read_us(get_us_ticker_data()));
|
||||||
|
|
||||||
|
utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
if (status != utest::v1::STATUS_CONTINUE) {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
char key[MSG_KEY_LEN + 1] = { };
|
||||||
|
char usb_dev_uuid[USB_DEV_SN_LEN + 1] = { };
|
||||||
|
|
||||||
|
greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY);
|
||||||
|
greentea_parse_kv(key, usb_dev_uuid, MSG_KEY_LEN, USB_DEV_SN_LEN + 1);
|
||||||
|
|
||||||
|
if (strcmp(key, MSG_KEY_SERIAL_NUMBER) != 0) {
|
||||||
|
utest_printf("Invalid message key.\n");
|
||||||
|
return utest::v1::STATUS_ABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
strncpy(usb_dev_sn, usb_dev_uuid, USB_DEV_SN_LEN + 1);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Configuration descriptor, generic", test_get_configuration_desc<TestUSBHID, USB_HID_PID_GENERIC>),
|
||||||
|
Case("Configuration descriptor, keyboard", test_get_configuration_desc<TestUSBKeyboard, USB_HID_PID_KEYBOARD>),
|
||||||
|
Case("Configuration descriptor, mouse", test_get_configuration_desc<TestUSBMouse, USB_HID_PID_MOUSE>),
|
||||||
|
|
||||||
|
Case("HID class descriptors, generic", test_get_hid_class_desc<TestUSBHID, USB_HID_PID_GENERIC>),
|
||||||
|
Case("HID class descriptors, keyboard", test_get_hid_class_desc<TestUSBKeyboard, USB_HID_PID_KEYBOARD>),
|
||||||
|
Case("HID class descriptors, mouse", test_get_hid_class_desc<TestUSBMouse, USB_HID_PID_MOUSE>),
|
||||||
|
|
||||||
|
// HID class requests not supported by Mbed
|
||||||
|
// Case("HID class requests, generic", test_class_requests<TestUSBHID, USB_HID_PID_GENERIC>),
|
||||||
|
// Case("HID class requests, keyboard", test_class_requests<TestUSBKeyboard, USB_HID_PID_KEYBOARD>),
|
||||||
|
// Case("HID class requests, mouse", test_class_requests<TestUSBMouse, USB_HID_PID_MOUSE>),
|
||||||
|
|
||||||
|
Case("Raw input/output, 1-byte reports", test_generic_raw_io<1>),
|
||||||
|
Case("Raw input/output, 20-byte reports", test_generic_raw_io<20>),
|
||||||
|
Case("Raw input/output, 64-byte reports", test_generic_raw_io<64>),
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
hidapi>=0.7.99,<0.8.0
|
|
@ -104,75 +104,148 @@ You can also set custom compiler flags and other configurations supported by CMa
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
With the following steps, you can write a simple unit test. In this example, `rtos/Semaphore.cpp` is a class under test.
|
With the following steps, you can write a simple unit test. This example creates dummy classes to be tested, creates and configures unit tests for a class and stubs all external dependencies.
|
||||||
|
|
||||||
1. Create a directory for unit test files in `UNITTESTS/rtos/Semaphore`.
|
1. Create the following dummy classes in `mbed-os/example`:
|
||||||
1. Create a test configuration file `UNITTESTS/rtos/Semaphore/unittest.cmake` with the following content:
|
|
||||||
|
|
||||||
```
|
**MyClass.h**
|
||||||
set(unittest-sources
|
|
||||||
../rtos/Semaphore.cpp
|
|
||||||
)
|
|
||||||
|
|
||||||
set(unittest-test-sources
|
|
||||||
stubs/mbed_assert_stub.c
|
|
||||||
stubs/Kernel_stub.cpp
|
|
||||||
rtos/Semaphore/test_Semaphore.cpp
|
|
||||||
)
|
|
||||||
```
|
|
||||||
1. Stub all external dependencies. Create stubs `UNITTESTS/stubs/mbed_assert_stub.c` and `UNITTESTS/stubs/Kernel_stub.cpp` if they don't already exist.
|
|
||||||
1. Update header stubs with any missing type or function declarations.
|
|
||||||
1. Create a test source file `UNITTESTS/rtos/Semaphore/test_Semaphore.cpp` with the following content:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
#include "gtest/gtest.h"
|
#ifndef MYCLASS_H_
|
||||||
#include "rtos/Semaphore.h"
|
#define MYCLASS_H_
|
||||||
|
|
||||||
static osStatus_t retval = osOK;
|
namespace example {
|
||||||
static uint32_t count = 0;
|
|
||||||
|
|
||||||
// Test stubs
|
class MyClass {
|
||||||
osStatus_t osSemaphoreAcquire(osSemaphoreId_t semaphore_id, uint32_t timeout)
|
public:
|
||||||
{
|
int myFunction();
|
||||||
return retval;
|
};
|
||||||
}
|
|
||||||
osStatus_t osSemaphoreDelete(osSemaphoreId_t semaphore_id)
|
|
||||||
{
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
osStatus_t osSemaphoreRelease(osSemaphoreId_t semaphore_id)
|
|
||||||
{
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
uint32_t osSemaphoreGetCount(osSemaphoreId_t semaphore_id)
|
|
||||||
{
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
osSemaphoreId_t osSemaphoreNew(uint32_t max_count, uint32_t initial_count, const osSemaphoreAttr_t *attr)
|
|
||||||
{
|
|
||||||
return (void *)&count; // Just a dymmy reference
|
|
||||||
}
|
|
||||||
|
|
||||||
class TestSemaphore : public testing::Test {
|
|
||||||
protected:
|
|
||||||
rtos::Semaphore *sem;
|
|
||||||
|
|
||||||
virtual void SetUp()
|
|
||||||
{
|
|
||||||
sem = new rtos::Semaphore();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void TearDown()
|
#endif
|
||||||
{
|
```
|
||||||
delete sem;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST_F(TestSemaphore, constructor)
|
**MyClass.cpp**
|
||||||
{
|
|
||||||
EXPECT_TRUE(sem);
|
```
|
||||||
}
|
#include "MyClass.h"
|
||||||
```
|
#include "OtherClass.h"
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
int MyClass::myFunction() {
|
||||||
|
OtherClass o = OtherClass();
|
||||||
|
return o.otherFunction();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**OtherClass.h**
|
||||||
|
|
||||||
|
```
|
||||||
|
#ifndef OTHERCLASS_H_
|
||||||
|
#define OTHERCLASS_H_
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
class OtherClass {
|
||||||
|
public:
|
||||||
|
int otherFunction();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
```
|
||||||
|
|
||||||
|
**OtherClass.cpp**
|
||||||
|
|
||||||
|
```
|
||||||
|
#include "OtherClass.h"
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
int OtherClass::otherFunction() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Create a directory for MyClass unit tests in `UNITTESTS/example/MyClass`.
|
||||||
|
1. Create a configuration file and a source file for MyClass unit tests in `UNITTESTS/example/MyClass`:
|
||||||
|
|
||||||
|
**unittest.cmake**
|
||||||
|
|
||||||
|
```
|
||||||
|
# Add here additional test specific include paths
|
||||||
|
set(unittest-includes ${unittest-includes}
|
||||||
|
../example
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add here classes under test
|
||||||
|
set(unittest-sources
|
||||||
|
../example/MyClass.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add here test classes and stubs
|
||||||
|
set(unittest-test-sources
|
||||||
|
example/MyClass/test_MyClass.cpp
|
||||||
|
stubs/OtherClass_stub.cpp
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
**test_MyClass.cpp**
|
||||||
|
|
||||||
|
```
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "example/MyClass.h"
|
||||||
|
|
||||||
|
class TestMyClass : public testing::Test {
|
||||||
|
protected:
|
||||||
|
example::MyClass *obj;
|
||||||
|
|
||||||
|
virtual void SetUp()
|
||||||
|
{
|
||||||
|
obj = new example::MyClass();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown()
|
||||||
|
{
|
||||||
|
delete obj;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(TestMyClass, constructor)
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(TestMyClass, myfunction)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(obj->myFunction(), 0);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
1. Stub all external dependencies. Create the following stub in `UNITTESTS/stubs`:
|
||||||
|
|
||||||
|
**OtherClass_stub.cpp**
|
||||||
|
|
||||||
|
```
|
||||||
|
#include "example/OtherClass.h"
|
||||||
|
|
||||||
|
namespace example {
|
||||||
|
|
||||||
|
int OtherClass::otherFunction() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This example does not use any Mbed OS code, but if your unit tests do, then remember to update header stubs in `UNITTESTS/target_h` and source stubs in `UNITTESTS/stubs` with any missing type or function declarations.
|
||||||
|
|
||||||
### Building and running unit tests
|
### Building and running unit tests
|
||||||
|
|
||||||
|
@ -187,6 +260,7 @@ Use Mbed CLI to build and run unit tests. For advanced use, you can run CMake an
|
||||||
* Add `-DCMAKE_MAKE_PROGRAM=<value>`, `-DCMAKE_CXX_COMPILER=<value>` and `-DCMAKE_C_COMPILER=<value>` to use a specific Make program and compilers.
|
* Add `-DCMAKE_MAKE_PROGRAM=<value>`, `-DCMAKE_CXX_COMPILER=<value>` and `-DCMAKE_C_COMPILER=<value>` to use a specific Make program and compilers.
|
||||||
* Add `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
|
* Add `-DCMAKE_BUILD_TYPE=Debug` for a debug build.
|
||||||
* Add `-DCOVERAGE=True` to add coverage compiler flags.
|
* Add `-DCOVERAGE=True` to add coverage compiler flags.
|
||||||
|
* Add `-Dgtest_disable_pthreads=ON` to run in a single thread.
|
||||||
* See the [CMake manual](https://cmake.org/cmake/help/v3.0/manual/cmake.1.html) for more information.
|
* See the [CMake manual](https://cmake.org/cmake/help/v3.0/manual/cmake.1.html) for more information.
|
||||||
1. Run a Make program to build tests.
|
1. Run a Make program to build tests.
|
||||||
|
|
||||||
|
|
|
@ -29,8 +29,11 @@
|
||||||
using namespace mbed;
|
using namespace mbed;
|
||||||
using namespace events;
|
using namespace events;
|
||||||
|
|
||||||
|
uint8_t urc_callback_count;
|
||||||
|
|
||||||
void urc_callback()
|
void urc_callback()
|
||||||
{
|
{
|
||||||
|
urc_callback_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void urc2_callback()
|
void urc2_callback()
|
||||||
|
@ -44,6 +47,7 @@ protected:
|
||||||
|
|
||||||
void SetUp()
|
void SetUp()
|
||||||
{
|
{
|
||||||
|
urc_callback_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TearDown()
|
void TearDown()
|
||||||
|
@ -954,16 +958,19 @@ TEST_F(TestATHandler, test_ATHandler_resp_start)
|
||||||
filehandle_stub_table_pos = 0;
|
filehandle_stub_table_pos = 0;
|
||||||
at.resp_start();
|
at.resp_start();
|
||||||
|
|
||||||
char table7[] = "urc: info\r\nresponseOK\r\n\0";
|
char table7[] = "urc: info\r\nresponse\r\nOK\r\n\0";
|
||||||
at.flush();
|
at.flush();
|
||||||
at.clear_error();
|
at.clear_error();
|
||||||
filehandle_stub_table = table7;
|
filehandle_stub_table = table7;
|
||||||
filehandle_stub_table_pos = 0;
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
at.set_urc_handler("urc: ", NULL);
|
mbed::Callback<void()> cb1(&urc_callback);
|
||||||
|
at.set_urc_handler("urc: ", cb1);
|
||||||
at.resp_start(); // recv_buff: "responseOK\r\n\0"
|
at.resp_start(); // recv_buff: "responseOK\r\n\0"
|
||||||
at.resp_stop(); // consumes to OKCRLF -> OK
|
at.resp_stop(); // consumes to OKCRLF -> OK
|
||||||
EXPECT_TRUE(at.get_last_error() == NSAPI_ERROR_OK);
|
EXPECT_TRUE(at.get_last_error() == NSAPI_ERROR_OK);
|
||||||
|
EXPECT_TRUE(urc_callback_count == 1);
|
||||||
|
urc_callback_count = 0;
|
||||||
|
|
||||||
char table8[] = "urc: info\r\nresponse\0";
|
char table8[] = "urc: info\r\nresponse\0";
|
||||||
at.flush();
|
at.flush();
|
||||||
|
@ -1060,9 +1067,22 @@ TEST_F(TestATHandler, test_ATHandler_resp_stop)
|
||||||
filehandle_stub_table = table3;
|
filehandle_stub_table = table3;
|
||||||
filehandle_stub_table_pos = 0;
|
filehandle_stub_table_pos = 0;
|
||||||
at.resp_start();
|
at.resp_start();
|
||||||
|
|
||||||
at.resp_stop();
|
at.resp_stop();
|
||||||
|
|
||||||
|
// Set stop tag for response to CRLF -> resp stop should stop on first CRLF
|
||||||
|
char table6[] = "line1\r\nline2\r\nOK\r\n";
|
||||||
|
filehandle_stub_table = table6;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
|
at.flush();
|
||||||
|
at.clear_error();
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
|
at.resp_start();
|
||||||
|
at.set_stop_tag("\r\n");
|
||||||
|
at.resp_stop();
|
||||||
|
EXPECT_TRUE(at.get_last_error() == NSAPI_ERROR_OK);
|
||||||
|
|
||||||
char table7[] = "ssssss\0";
|
char table7[] = "ssssss\0";
|
||||||
filehandle_stub_table = table7;
|
filehandle_stub_table = table7;
|
||||||
filehandle_stub_table_pos = 0;
|
filehandle_stub_table_pos = 0;
|
||||||
|
@ -1072,6 +1092,38 @@ TEST_F(TestATHandler, test_ATHandler_resp_stop)
|
||||||
filehandle_stub_table_pos = 0;
|
filehandle_stub_table_pos = 0;
|
||||||
at.resp_start("ss", false);
|
at.resp_start("ss", false);
|
||||||
at.resp_stop();
|
at.resp_stop();
|
||||||
|
|
||||||
|
// prefix + URC line + some other line + URC line + URC line + OKCRLF
|
||||||
|
char table4[] = "line1\r\nline2abcd\r\nline3abcd\r\nline4\r\n\r\nline3\r\nline3\r\nOK\r\n";
|
||||||
|
filehandle_stub_table = table4;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
|
at.flush();
|
||||||
|
at.clear_error();
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed::Callback<void()> cb1(&urc_callback);
|
||||||
|
at.set_urc_handler("line3", cb1);
|
||||||
|
|
||||||
|
at.resp_start("line2");
|
||||||
|
at.resp_stop();
|
||||||
|
EXPECT_TRUE(urc_callback_count == 3);
|
||||||
|
urc_callback_count = 0;
|
||||||
|
|
||||||
|
// URC line + prefix + URC line + some other line + URC line + URC line + some other line + OKCRLF
|
||||||
|
char table5[] = "line1\r\nline3\r\nline2abcd\r\nline3abcd\r\nline4\r\n\r\nline3\r\nline3\r\nline4\r\nOK\r\n";
|
||||||
|
filehandle_stub_table = table5;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
|
at.flush();
|
||||||
|
at.clear_error();
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed::Callback<void()> cb2(&urc_callback);
|
||||||
|
at.set_urc_handler("line3", cb2);
|
||||||
|
|
||||||
|
at.resp_start("line2");
|
||||||
|
at.resp_stop();
|
||||||
|
EXPECT_TRUE(urc_callback_count == 4);
|
||||||
|
urc_callback_count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(TestATHandler, test_ATHandler_info_resp)
|
TEST_F(TestATHandler, test_ATHandler_info_resp)
|
||||||
|
|
|
@ -73,9 +73,9 @@ public:
|
||||||
_state_machine = NULL;
|
_state_machine = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
CellularStateMachine *create_state_machine(CellularDevice &device, events::EventQueue &queue)
|
CellularStateMachine *create_state_machine(CellularDevice &device, events::EventQueue &queue, CellularNetwork &nw)
|
||||||
{
|
{
|
||||||
_state_machine = new CellularStateMachine(device, queue);
|
_state_machine = new CellularStateMachine(device, queue, nw);
|
||||||
return _state_machine;
|
return _state_machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +171,7 @@ TEST_F(TestCellularStateMachine, test_create_delete)
|
||||||
CellularDevice *dev = new myCellularDevice(&fh1);
|
CellularDevice *dev = new myCellularDevice(&fh1);
|
||||||
EXPECT_TRUE(dev);
|
EXPECT_TRUE(dev);
|
||||||
|
|
||||||
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue());
|
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
ut.delete_state_machine();
|
ut.delete_state_machine();
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ TEST_F(TestCellularStateMachine, test_setters)
|
||||||
CellularDevice *dev = new myCellularDevice(&fh1);
|
CellularDevice *dev = new myCellularDevice(&fh1);
|
||||||
EXPECT_TRUE(dev);
|
EXPECT_TRUE(dev);
|
||||||
|
|
||||||
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue());
|
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
ut.set_cellular_callback(&cellular_callback);
|
ut.set_cellular_callback(&cellular_callback);
|
||||||
|
|
||||||
|
@ -215,14 +215,14 @@ TEST_F(TestCellularStateMachine, test_start_dispatch)
|
||||||
CellularDevice *dev = new myCellularDevice(&fh1);
|
CellularDevice *dev = new myCellularDevice(&fh1);
|
||||||
EXPECT_TRUE(dev);
|
EXPECT_TRUE(dev);
|
||||||
|
|
||||||
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue());
|
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
nsapi_error_t err = ut.start_dispatch();
|
nsapi_error_t err = ut.start_dispatch();
|
||||||
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
||||||
ut.delete_state_machine();
|
ut.delete_state_machine();
|
||||||
|
|
||||||
Thread_stub::osStatus_value = osErrorNoMemory;
|
Thread_stub::osStatus_value = osErrorNoMemory;
|
||||||
stm = ut.create_state_machine(*dev, *dev->get_queue());
|
stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
err = ut.start_dispatch();
|
err = ut.start_dispatch();
|
||||||
ASSERT_EQ(NSAPI_ERROR_NO_MEMORY, err);
|
ASSERT_EQ(NSAPI_ERROR_NO_MEMORY, err);
|
||||||
|
@ -240,13 +240,13 @@ TEST_F(TestCellularStateMachine, test_stop)
|
||||||
CellularDevice *dev = new AT_CellularDevice(&fh1);
|
CellularDevice *dev = new AT_CellularDevice(&fh1);
|
||||||
EXPECT_TRUE(dev);
|
EXPECT_TRUE(dev);
|
||||||
|
|
||||||
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue());
|
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
|
|
||||||
ut.stop(); // nothing created, run through
|
ut.stop(); // nothing created, run through
|
||||||
ut.delete_state_machine();
|
ut.delete_state_machine();
|
||||||
|
|
||||||
stm = ut.create_state_machine(*dev, *dev->get_queue());
|
stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
nsapi_error_t err = ut.start_dispatch();
|
nsapi_error_t err = ut.start_dispatch();
|
||||||
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
||||||
|
@ -254,7 +254,7 @@ TEST_F(TestCellularStateMachine, test_stop)
|
||||||
ut.stop(); // thread is created, now stop will delete it
|
ut.stop(); // thread is created, now stop will delete it
|
||||||
ut.delete_state_machine();
|
ut.delete_state_machine();
|
||||||
|
|
||||||
stm = ut.create_state_machine(*dev, *dev->get_queue());
|
stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
err = ut.start_dispatch();
|
err = ut.start_dispatch();
|
||||||
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
||||||
|
@ -270,7 +270,7 @@ TEST_F(TestCellularStateMachine, test_stop)
|
||||||
ut.stop(); // thread and power are created, now stop will delete them
|
ut.stop(); // thread and power are created, now stop will delete them
|
||||||
ut.delete_state_machine();
|
ut.delete_state_machine();
|
||||||
|
|
||||||
stm = ut.create_state_machine(*dev, *dev->get_queue());
|
stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
err = ut.start_dispatch();
|
err = ut.start_dispatch();
|
||||||
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
ASSERT_EQ(NSAPI_ERROR_OK, err);
|
||||||
|
@ -294,7 +294,7 @@ TEST_F(TestCellularStateMachine, test_run_to_state)
|
||||||
CellularDevice *dev = new AT_CellularDevice(&fh1);
|
CellularDevice *dev = new AT_CellularDevice(&fh1);
|
||||||
EXPECT_TRUE(dev);
|
EXPECT_TRUE(dev);
|
||||||
|
|
||||||
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue());
|
CellularStateMachine *stm = ut.create_state_machine(*dev, *dev->get_queue(), *dev->open_network());
|
||||||
EXPECT_TRUE(stm);
|
EXPECT_TRUE(stm);
|
||||||
|
|
||||||
nsapi_error_t err = ut.start_dispatch();
|
nsapi_error_t err = ut.start_dispatch();
|
||||||
|
|
|
@ -25,8 +25,8 @@ CellularStubState CellularStateMachine_stub::get_current_target_state = STATE_IN
|
||||||
CellularStubState CellularStateMachine_stub::get_current_current_state = STATE_INIT;
|
CellularStubState CellularStateMachine_stub::get_current_current_state = STATE_INIT;
|
||||||
bool CellularStateMachine_stub::bool_value = false;
|
bool CellularStateMachine_stub::bool_value = false;
|
||||||
|
|
||||||
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue) :
|
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue, CellularNetwork &nw) :
|
||||||
_cellularDevice(device), _queue(queue)
|
_cellularDevice(device), _network(nw), _queue(queue)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,11 +6,9 @@
|
||||||
*/
|
*/
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "rtx_os.h"
|
#include "rtx_os.h"
|
||||||
#include "cmsis_os2.h"
|
#include "cmsis_os2.h"
|
||||||
|
|
||||||
#include "tfm_api.h"
|
#include "tfm_api.h"
|
||||||
#include "tfm_ns_lock.h"
|
#include "tfm_ns_lock.h"
|
||||||
|
|
||||||
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __BOOT_RECORD_H__
|
|
||||||
#define __BOOT_RECORD_H__
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \enum shared_data_err_t
|
|
||||||
*
|
|
||||||
* \brief Return values for adding data entry to shared memory area
|
|
||||||
*/
|
|
||||||
enum shared_memory_err_t {
|
|
||||||
SHARED_MEMORY_OK = 0,
|
|
||||||
SHARED_MEMORY_OVERFLOW = 1,
|
|
||||||
SHARED_MEMORY_OVERWRITE = 2,
|
|
||||||
|
|
||||||
/* This is used to force the maximum size */
|
|
||||||
TLV_TYPE_MAX = INT_MAX
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Add a data item to the shared data area between bootloader and
|
|
||||||
* runtime SW
|
|
||||||
*
|
|
||||||
* \param[in] major_type TLV major type, identify consumer
|
|
||||||
* \param[in] minor_type TLV minor type, identify TLV type
|
|
||||||
* \param[in] size length of added data
|
|
||||||
* \param[in] data pointer to data
|
|
||||||
*
|
|
||||||
* \return Returns error code as specified in \ref shared_memory_err_t
|
|
||||||
*/
|
|
||||||
enum shared_memory_err_t
|
|
||||||
boot_add_data_to_shared_area(uint8_t major_type,
|
|
||||||
uint8_t minor_type,
|
|
||||||
size_t size,
|
|
||||||
const uint8_t *data);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* __BOOT_RECORD_H__ */
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
|
@ -16,43 +16,165 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Major numbers to identify the consumer of shared data in runtime SW */
|
/* Major numbers (4 bit) to identify
|
||||||
#define TLV_MAJOR_CORE 0x0
|
* the consumer of shared data in runtime SW
|
||||||
#define TLV_MAJOR_IAS 0x1
|
*/
|
||||||
|
#define TLV_MAJOR_CORE 0x0
|
||||||
|
#define TLV_MAJOR_IAS 0x1
|
||||||
|
|
||||||
/* PSA Root of Trust */
|
/**
|
||||||
#define TLV_MINOR_IAS_PRoT_SHA256 0x00
|
* The shared data between boot loader and runtime SW is TLV encoded. The
|
||||||
#define TLV_MINOR_IAS_PRoT_SW_VERSION 0x01
|
* shared data is stored in a well known location in secure memory and this is
|
||||||
#define TLV_MINOR_IAS_PRoT_EPOCH 0x02
|
* a contract between boot loader and runtime SW.
|
||||||
|
*
|
||||||
|
* The structure of shared data must be the following:
|
||||||
|
* - At the beginning there must be a header: struct shared_data_tlv_header
|
||||||
|
* This contains a magic number and a size field which covers the entire
|
||||||
|
* size of the shared data area including this header.
|
||||||
|
* - After the header there come the entries which are composed from an entry
|
||||||
|
* header structure: struct shared_data_tlv_entry and the data. In the entry
|
||||||
|
* header is a type field (tly_type) which identify the consumer of the
|
||||||
|
* entry in the runtime SW and specify the subtype of that data item. There
|
||||||
|
* is a size field (tlv_len) which covers the size of the entry header and
|
||||||
|
* the data. After this structure comes the actual data.
|
||||||
|
* - Arbitrary number and size of data entry can be in the shared memory area.
|
||||||
|
*
|
||||||
|
* This table gives of overview about the tlv_type field in the entry header.
|
||||||
|
* The tlv_type always composed from a major and minor number. Major number
|
||||||
|
* identifies the addressee in runtime SW, who should process the data entry.
|
||||||
|
* Minor number used to encode more info about the data entry. The actual
|
||||||
|
* definition of minor number could change per major number. In case of boot
|
||||||
|
* status data, which is going to be processed by initial attestation service
|
||||||
|
* the minor number is split further to two part: sw_module and claim. The
|
||||||
|
* sw_module identifies the SW component in the system which the data item
|
||||||
|
* belongs to and the claim part identifies the exact type of the data.
|
||||||
|
*
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | tlv_type (16) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | tlv_major(4)| tlv_minor(12) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | MAJOR_IAS | sw_module(6) | claim(6) |
|
||||||
|
* |---------------------------------------|
|
||||||
|
* | MAJOR_CORE | TBD |
|
||||||
|
* |---------------------------------------|
|
||||||
|
*/
|
||||||
|
|
||||||
/* Application Root of Trust */
|
/* Initial attestation: SW components / SW modules
|
||||||
#define TLV_MINOR_IAS_ARoT_SHA256 0x03
|
* This list is intended to be adjusted per device. It contains more SW
|
||||||
#define TLV_MINOR_IAS_ARoT_SW_VERSION 0x04
|
* components than currently available in TF-M project. It serves as an example,
|
||||||
#define TLV_MINOR_IAS_ARoT_EPOCH 0x05
|
* what kind of SW components might be available.
|
||||||
|
*/
|
||||||
|
#define SW_GENERAL 0x00
|
||||||
|
#define SW_BL2 0x01
|
||||||
|
#define SW_PROT 0x02
|
||||||
|
#define SW_AROT 0x03
|
||||||
|
#define SW_SPE 0x04
|
||||||
|
#define SW_NSPE 0x05
|
||||||
|
#define SW_S_NS 0x06
|
||||||
|
#define SW_MAX 0x07
|
||||||
|
|
||||||
/* Non-secure processing environment: single non-secure image */
|
/* Initial attestation: Claim per SW components / SW modules */
|
||||||
#define TLV_MINOR_IAS_NSPE_SHA256 0x06
|
/* Bits: 0-2 */
|
||||||
#define TLV_MINOR_IAS_NSPE_SW_VERSION 0x07
|
#define SW_VERSION 0x00
|
||||||
#define TLV_MINOR_IAS_NSPE_EPOCH 0x08
|
#define SW_SIGNER_ID 0x01
|
||||||
|
#define SW_EPOCH 0x02
|
||||||
|
#define SW_TYPE 0x03
|
||||||
|
/* Bits: 3-5 */
|
||||||
|
#define SW_MEASURE_VALUE 0x08
|
||||||
|
#define SW_MEASURE_TYPE 0x09
|
||||||
|
|
||||||
/* ARoT + PRoT: single secure image */
|
/* Initial attestation: General claim does not belong any particular SW
|
||||||
#define TLV_MINOR_IAS_S_SHA256 0x09
|
* component. But they might be part of the boot status.
|
||||||
#define TLV_MINOR_IAS_S_SW_VERSION 0x0a
|
*/
|
||||||
#define TLV_MINOR_IAS_S_EPOCH 0x0b
|
#define BOOT_SEED 0x00
|
||||||
|
#define HW_VERSION 0x01
|
||||||
|
#define SECURITY_LIFECYCLE 0x02
|
||||||
|
|
||||||
/* S + NS: combined secure and non-secure image */
|
/* Minor numbers (12 bit) to identify attestation service related data */
|
||||||
#define TLV_MINOR_IAS_S_NS_SHA256 0x0c
|
#define TLV_MINOR_IAS_BOOT_SEED ((SW_GENERAL << 6) | BOOT_SEED)
|
||||||
#define TLV_MINOR_IAS_S_NS_SW_VERSION 0x0d
|
#define TLV_MINOR_IAS_HW_VERSION ((SW_GENERAL << 6) | HW_VERSION)
|
||||||
#define TLV_MINOR_IAS_S_NS_EPOCH 0x0e
|
#define TLV_MINOR_IAS_SLC ((SW_GENERAL << 6) | SECURITY_LIFECYCLE)
|
||||||
|
|
||||||
|
/* Bootloader - It can be more stage */
|
||||||
|
#define TLV_MINOR_IAS_BL2_MEASURE_VALUE ((SW_BL2 << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_BL2_MEASURE_TYPE ((SW_BL2 << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_BL2_VERSION ((SW_BL2 << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_BL2_SIGNER_ID ((SW_BL2 << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_BL2_EPOCH ((SW_BL2 << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_BL2_TYPE ((SW_BL2 << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* PROT: PSA Root of Trust */
|
||||||
|
#define TLV_MINOR_IAS_PROT_MEASURE_VALUE ((SW_PROT << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_PROT_MEASURE_TYPE ((SW_PROT << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_PROT_VERSION ((SW_PROT << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_PROT_SIGNER_ID ((SW_PROT << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_PROT_EPOCH ((SW_PROT << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_PROT_TYPE ((SW_PROT << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* AROT: Application Root of Trust */
|
||||||
|
#define TLV_MINOR_IAS_AROT_MEASURE_VALUE ((SW_AROT << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_AROT_MEASURE_TYPE ((SW_AROT << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_AROT_VERSION ((SW_AROT << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_AROT_SIGNER_ID ((SW_AROT << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_AROT_EPOCH ((SW_AROT << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_AROT_TYPE ((SW_AROT << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* Non-secure processing environment - single non-secure image */
|
||||||
|
#define TLV_MINOR_IAS_NSPE_MEASURE_VALUE ((SW_NSPE << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_NSPE_MEASURE_TYPE ((SW_NSPE << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_NSPE_VERSION ((SW_NSPE << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_NSPE_SIGNER_ID ((SW_NSPE << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_NSPE_EPOCH ((SW_NSPE << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_NSPE_TYPE ((SW_NSPE << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* Secure processing environment (ARoT + PRoT) - single secure image */
|
||||||
|
#define TLV_MINOR_IAS_SPE_MEASURE_VALUE ((SW_SPE << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_SPE_MEASURE_TYPE ((SW_SPE << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_SPE_VERSION ((SW_SPE << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_SPE_SIGNER_ID ((SW_SPE << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_SPE_EPOCH ((SW_SPE << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_SPE_TYPE ((SW_SPE << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* SPE + NSPE - combined secure and non-secure image */
|
||||||
|
#define TLV_MINOR_IAS_S_NS_MEASURE_VALUE ((SW_S_NS << 6) | SW_MEASURE_VALUE)
|
||||||
|
#define TLV_MINOR_IAS_S_NS_MEASURE_TYPE ((SW_S_NS << 6) | SW_MEASURE_TYPE)
|
||||||
|
#define TLV_MINOR_IAS_S_NS_VERSION ((SW_S_NS << 6) | SW_VERSION)
|
||||||
|
#define TLV_MINOR_IAS_S_NS_SIGNER_ID ((SW_S_NS << 6) | SW_SIGNER_ID)
|
||||||
|
#define TLV_MINOR_IAS_S_NS_EPOCH ((SW_S_NS << 6) | SW_EPOCH)
|
||||||
|
#define TLV_MINOR_IAS_S_NS_TYPE ((SW_S_NS << 6) | SW_TYPE)
|
||||||
|
|
||||||
|
/* General macros to handle TLV type */
|
||||||
|
#define MAJOR_MASK 0xF /* 4 bit */
|
||||||
|
#define MAJOR_POS 12 /* 12 bit */
|
||||||
|
#define MINOR_MASK 0xFFF /* 12 bit */
|
||||||
|
|
||||||
|
#define SET_TLV_TYPE(major, minor) \
|
||||||
|
((((major) & MAJOR_MASK) << MAJOR_POS) | ((minor) & MINOR_MASK))
|
||||||
|
#define GET_MAJOR(tlv_type) ((tlv_type) >> MAJOR_POS)
|
||||||
|
#define GET_MINOR(tlv_type) ((tlv_type) & MINOR_MASK)
|
||||||
|
|
||||||
|
/* Initial attestation specific macros */
|
||||||
|
#define MODULE_POS 6 /* 6 bit */
|
||||||
|
#define CLAIM_MASK 0x3F /* 6 bit */
|
||||||
|
#define MEASUREMENT_CLAIM_POS 3 /* 3 bit */
|
||||||
|
|
||||||
|
#define GET_IAS_MODULE(tlv_type) (GET_MINOR(tlv_type) >> MODULE_POS)
|
||||||
|
#define GET_IAS_CLAIM(tlv_type) (GET_MINOR(tlv_type) & CLAIM_MASK)
|
||||||
|
#define SET_IAS_MINOR(sw_module, claim) (((sw_module) << 6) | (claim))
|
||||||
|
|
||||||
|
#define GET_IAS_MEASUREMENT_CLAIM(ias_claim) ((ias_claim) >> \
|
||||||
|
MEASUREMENT_CLAIM_POS)
|
||||||
|
|
||||||
|
/* Magic value which marks the beginning of shared data area in memory */
|
||||||
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
|
#define SHARED_DATA_TLV_INFO_MAGIC 0x2016
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shared data TLV header. All fields in little endian.
|
* Shared data TLV header. All fields in little endian.
|
||||||
*
|
*
|
||||||
* ---------------------------
|
* -----------------------------------
|
||||||
* | tlv_magic | tlv_tot_len |
|
* | tlv_magic(16) | tlv_tot_len(16) |
|
||||||
* ---------------------------
|
* -----------------------------------
|
||||||
*/
|
*/
|
||||||
struct shared_data_tlv_header {
|
struct shared_data_tlv_header {
|
||||||
uint16_t tlv_magic;
|
uint16_t tlv_magic;
|
||||||
|
@ -64,15 +186,14 @@ struct shared_data_tlv_header {
|
||||||
/**
|
/**
|
||||||
* Shared data TLV entry header format. All fields in little endian.
|
* Shared data TLV entry header format. All fields in little endian.
|
||||||
*
|
*
|
||||||
* ---------------------------------------------
|
* -------------------------------
|
||||||
* | tlv_major_type | tlv_minor_type | tlv_len |
|
* | tlv_type(16) | tlv_len(16) |
|
||||||
* ---------------------------------------------
|
* -------------------------------
|
||||||
* | Raw data |
|
* | Raw data |
|
||||||
* ---------------------------------------------
|
* -------------------------------
|
||||||
*/
|
*/
|
||||||
struct shared_data_tlv_entry {
|
struct shared_data_tlv_entry {
|
||||||
uint8_t tlv_major_type;
|
uint16_t tlv_type;
|
||||||
uint8_t tlv_minor_type;
|
|
||||||
uint16_t tlv_len; /* size of single TLV entry (including this header). */
|
uint16_t tlv_len; /* size of single TLV entry (including this header). */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
//This file holds description for the current directory. This documentation
|
||||||
|
//will be included in the Doxygen output.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\dir
|
||||||
|
\brief Source code for the TF-M core.
|
||||||
|
\details This directory holds the source code of the "TF-M core" module.
|
||||||
|
|
||||||
|
*/
|
|
@ -16,7 +16,7 @@ struct tfm_msg_body_t {
|
||||||
int32_t magic;
|
int32_t magic;
|
||||||
struct tfm_spm_service_t *service; /* RoT service pointer */
|
struct tfm_spm_service_t *service; /* RoT service pointer */
|
||||||
psa_handle_t handle; /* Connected Service handle */
|
psa_handle_t handle; /* Connected Service handle */
|
||||||
struct tfm_event_ctx ack_mtx; /* Event for ack reponse */
|
struct tfm_event_t ack_evnt; /* Event for ack reponse */
|
||||||
psa_msg_t msg; /* PSA message body */
|
psa_msg_t msg; /* PSA message body */
|
||||||
psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body */
|
psa_invec invec[PSA_MAX_IOVEC]; /* Put in/out vectors in msg body */
|
||||||
psa_outvec outvec[PSA_MAX_IOVEC];
|
psa_outvec outvec[PSA_MAX_IOVEC];
|
||||||
|
|
|
@ -59,7 +59,7 @@ struct tfm_spm_service_t {
|
||||||
struct tfm_spm_ipc_partition_t {
|
struct tfm_spm_ipc_partition_t {
|
||||||
int32_t index; /* Partition index */
|
int32_t index; /* Partition index */
|
||||||
int32_t id; /* Secure partition ID */
|
int32_t id; /* Secure partition ID */
|
||||||
struct tfm_event_ctx signal_event; /* Event signal */
|
struct tfm_event_t signal_evnt; /* Event signal */
|
||||||
uint32_t signals; /* Service signals had been triggered*/
|
uint32_t signals; /* Service signals had been triggered*/
|
||||||
uint32_t signal_mask; /* Service signal mask passed by psa_wait() */
|
uint32_t signal_mask; /* Service signal mask passed by psa_wait() */
|
||||||
struct tfm_list_node_t service_list;/* Service list */
|
struct tfm_list_node_t service_list;/* Service list */
|
||||||
|
|
|
@ -58,7 +58,7 @@ psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller);
|
||||||
* handle, in_vec, in_len, out_vec, out_len.
|
* handle, in_vec, in_len, out_vec, out_len.
|
||||||
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
* \param[in] ns_caller If 'non-zero', call from non-secure client.
|
||||||
* Or from secure client.
|
* Or from secure client.
|
||||||
* \param[in] lr Link register to be stored
|
* \param[in] lr EXC_RETURN value of the SVC.
|
||||||
*
|
*
|
||||||
* \retval >=0 RoT Service-specific status value.
|
* \retval >=0 RoT Service-specific status value.
|
||||||
* \retval <0 RoT Service-specific error code.
|
* \retval <0 RoT Service-specific error code.
|
||||||
|
@ -74,7 +74,8 @@ psa_handle_t tfm_svcall_psa_connect(uint32_t *args, int32_t ns_caller);
|
||||||
* \arg The message is unrecognized by the RoT
|
* \arg The message is unrecognized by the RoT
|
||||||
* Service or incorrectly formatted.
|
* Service or incorrectly formatted.
|
||||||
*/
|
*/
|
||||||
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller, uint32_t lr);
|
psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller,
|
||||||
|
uint32_t lr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief SVC handler for \ref psa_close.
|
* \brief SVC handler for \ref psa_close.
|
||||||
|
@ -97,7 +98,7 @@ void tfm_svcall_psa_close(uint32_t *args, int32_t ns_caller);
|
||||||
*
|
*
|
||||||
* \param[in] svc_num SVC number
|
* \param[in] svc_num SVC number
|
||||||
* \param[in] ctx Argument context
|
* \param[in] ctx Argument context
|
||||||
* \param[in] lr Link register to be stored
|
* \param[in] lr EXC_RETURN value of the SVC.
|
||||||
*
|
*
|
||||||
* \returns Return values from those who has,
|
* \returns Return values from those who has,
|
||||||
* or PSA_SUCCESS.
|
* or PSA_SUCCESS.
|
||||||
|
|
|
@ -9,78 +9,47 @@
|
||||||
|
|
||||||
#include "cmsis_compiler.h"
|
#include "cmsis_compiler.h"
|
||||||
|
|
||||||
#define EVENT_MAGIC 0x65766e74
|
/* The magic number has two purposes: corruption detection and debug */
|
||||||
#define EVENT_STAT_WAITED 0x0
|
#define TFM_EVENT_MAGIC 0x65766e74
|
||||||
#define EVENT_STAT_SIGNALED 0x1
|
|
||||||
|
|
||||||
struct tfm_event_ctx {
|
struct tfm_event_t {
|
||||||
uint32_t magic; /* 'evnt' */
|
uint32_t magic; /* 'evnt' */
|
||||||
struct tfm_thrd_ctx *owner; /* waiting thread */
|
struct tfm_thrd_ctx *owner; /* Event blocked thread */
|
||||||
uint32_t status; /* status */
|
|
||||||
uint32_t retval; /* return value */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize an event context.
|
* Initialize an event object.
|
||||||
*
|
*
|
||||||
* Parameters :
|
* Parameters:
|
||||||
* pevt - pointer of event context caller provided
|
* pevnt - The pointer of event object allocated by the caller
|
||||||
* stat - initial status (EVENT_STAT_WAITED or EVENT_STAT_SIGNALED)
|
|
||||||
*/
|
*/
|
||||||
void __STATIC_INLINE tfm_event_init(struct tfm_event_ctx *pevt, uint32_t stat)
|
void __STATIC_INLINE tfm_event_init(struct tfm_event_t *pevnt)
|
||||||
{
|
{
|
||||||
pevt->magic = EVENT_MAGIC;
|
pevnt->magic = TFM_EVENT_MAGIC;
|
||||||
pevt->status = stat;
|
pevnt->owner = NULL;
|
||||||
pevt->owner = NULL;
|
|
||||||
pevt->retval = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait on an event.
|
* Wait on an event object.
|
||||||
*
|
*
|
||||||
* Parameters :
|
* Parameters:
|
||||||
* pevt - pointer of event context
|
* pevnt - The pointer of event object allocated by the caller
|
||||||
*
|
*
|
||||||
* Notes :
|
* Notes:
|
||||||
* Thread is blocked if event is not signaled.
|
* Block caller thread by calling this function.
|
||||||
*/
|
*/
|
||||||
void tfm_event_wait(struct tfm_event_ctx *pevt);
|
void tfm_event_wait(struct tfm_event_t *pevnt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Signal an event.
|
* Wake up an event object.
|
||||||
*
|
*
|
||||||
* Parameters :
|
* Parameters :
|
||||||
* pevt - pointer of event context
|
* pevnt - The pointer of event object allocated by the caller
|
||||||
|
* retval - Value to be returned to owner
|
||||||
*
|
*
|
||||||
* Notes :
|
* Notes:
|
||||||
* Waiting thread on this event will be running.
|
* Wake up the blocked thread and set parameter 'retval' as the return value.
|
||||||
*/
|
*/
|
||||||
void tfm_event_signal(struct tfm_event_ctx *pevt);
|
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval);
|
||||||
|
|
||||||
/*
|
|
||||||
* Peek an event status.
|
|
||||||
*
|
|
||||||
* Parameters :
|
|
||||||
* pevt - pointer of event context
|
|
||||||
*
|
|
||||||
* Return :
|
|
||||||
* Status of event.
|
|
||||||
*
|
|
||||||
* Notes :
|
|
||||||
* This function is used for getting event status without blocking thread.
|
|
||||||
*/
|
|
||||||
uint32_t tfm_event_peek(struct tfm_event_ctx *pevt);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set event owner return value.
|
|
||||||
*
|
|
||||||
* Parameters :
|
|
||||||
* pevt - pointer of event context
|
|
||||||
* retval - return value of blocked owner thread
|
|
||||||
*
|
|
||||||
* Notes :
|
|
||||||
* Thread return value is set while thread is to be running.
|
|
||||||
*/
|
|
||||||
void tfm_event_owner_retval(struct tfm_event_ctx *pevt, uint32_t retval);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
#include "cmsis.h"
|
#include "cmsis.h"
|
||||||
#include "psa_client.h"
|
#include "psa_client.h"
|
||||||
#include "psa_service.h"
|
#include "psa_service.h"
|
||||||
#include "secure_utilities.h"
|
|
||||||
#include "tfm_utils.h"
|
#include "tfm_utils.h"
|
||||||
#include "tfm_thread.h"
|
#include "tfm_thread.h"
|
||||||
|
#include "tfm_memory_utils.h"
|
||||||
|
|
||||||
/* This file contains the ARCH code for ARM V8M */
|
/* This file contains the ARCH code for ARM V8M */
|
||||||
|
|
||||||
|
@ -91,6 +91,7 @@ void tfm_initialize_context(struct tfm_state_context *ctx,
|
||||||
* thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
|
* thread SP/SP_LIMIT. R2 holds dummy data due to stack operation is 8 bytes
|
||||||
* aligned.
|
* aligned.
|
||||||
*/
|
*/
|
||||||
|
#if defined(__ARM_ARCH_8M_MAIN__)
|
||||||
__attribute__((naked)) void PendSV_Handler(void)
|
__attribute__((naked)) void PendSV_Handler(void)
|
||||||
{
|
{
|
||||||
__ASM(
|
__ASM(
|
||||||
|
@ -107,6 +108,37 @@ __attribute__((naked)) void PendSV_Handler(void)
|
||||||
"bx lr \n"
|
"bx lr \n"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
#elif defined(__ARM_ARCH_8M_BASE__)
|
||||||
|
__attribute__((naked)) void PendSV_Handler(void)
|
||||||
|
{
|
||||||
|
__ASM(
|
||||||
|
"mrs r0, psp \n"
|
||||||
|
"mrs r1, psplim \n"
|
||||||
|
"push {r0, r1, r2, lr} \n"
|
||||||
|
"push {r4-r7} \n"
|
||||||
|
"mov r4, r8 \n"
|
||||||
|
"mov r5, r9 \n"
|
||||||
|
"mov r6, r10 \n"
|
||||||
|
"mov r7, r11 \n"
|
||||||
|
"push {r4-r7} \n"
|
||||||
|
"mov r0, sp \n"
|
||||||
|
"bl tfm_pendsv_do_schedule \n"
|
||||||
|
"pop {r4-r7} \n"
|
||||||
|
"mov r8, r4 \n"
|
||||||
|
"mov r9, r5 \n"
|
||||||
|
"mov r10, r6 \n"
|
||||||
|
"mov r11, r7 \n"
|
||||||
|
"pop {r4-r7} \n"
|
||||||
|
"pop {r0-r3} \n"
|
||||||
|
"mov lr, r3 \n"
|
||||||
|
"msr psp, r0 \n"
|
||||||
|
"msr psplim, r1 \n"
|
||||||
|
"bx lr \n"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "Unsupported ARM Architecture."
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Reserved for future usage */
|
/* Reserved for future usage */
|
||||||
__attribute__((naked)) void MemManage_Handler(void)
|
__attribute__((naked)) void MemManage_Handler(void)
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
#include "tfm_utils.h"
|
#include "tfm_utils.h"
|
||||||
#include "tfm_list.h"
|
#include "tfm_list.h"
|
||||||
#include "tfm_pools.h"
|
#include "tfm_pools.h"
|
||||||
#include "secure_utilities.h"
|
#include "tfm_memory_utils.h"
|
||||||
|
|
||||||
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
|
int32_t tfm_pool_init(struct tfm_pool_instance_t *pool, size_t poolsz,
|
||||||
size_t chunksz, size_t num)
|
size_t chunksz, size_t num)
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "tfm_thread.h"
|
#include "tfm_thread.h"
|
||||||
#include "region_defs.h"
|
#include "region_defs.h"
|
||||||
#include "tfm_nspm.h"
|
#include "tfm_nspm.h"
|
||||||
|
#include "tfm_memory_utils.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IPC partitions.
|
* IPC partitions.
|
||||||
|
@ -348,7 +349,7 @@ struct tfm_msg_body_t *tfm_spm_create_msg(struct tfm_spm_service_t *service,
|
||||||
/* Clear message buffer before using it */
|
/* Clear message buffer before using it */
|
||||||
tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
|
tfm_memset(msg, 0, sizeof(struct tfm_msg_body_t));
|
||||||
|
|
||||||
tfm_event_init(&msg->ack_mtx, EVENT_STAT_WAITED);
|
tfm_event_init(&msg->ack_evnt);
|
||||||
msg->magic = TFM_MSG_MAGIC;
|
msg->magic = TFM_MSG_MAGIC;
|
||||||
msg->service = service;
|
msg->service = service;
|
||||||
msg->handle = handle;
|
msg->handle = handle;
|
||||||
|
@ -405,15 +406,11 @@ int32_t tfm_spm_send_event(struct tfm_spm_service_t *service,
|
||||||
/* Messages put. Update signals */
|
/* Messages put. Update signals */
|
||||||
service->partition->signals |= service->service_db->signal;
|
service->partition->signals |= service->service_db->signal;
|
||||||
|
|
||||||
/* Save return value for blocked threads */
|
tfm_event_wake(&service->partition->signal_evnt,
|
||||||
tfm_event_owner_retval(&service->partition->signal_event,
|
(service->partition->signals &
|
||||||
service->partition->signals &
|
service->partition->signal_mask));
|
||||||
service->partition->signal_mask);
|
|
||||||
|
|
||||||
/* Wake waiting thread up */
|
tfm_event_wait(&msg->ack_evnt);
|
||||||
tfm_event_signal(&service->partition->signal_event);
|
|
||||||
|
|
||||||
tfm_event_wait(&msg->ack_mtx);
|
|
||||||
|
|
||||||
return IPC_SUCCESS;
|
return IPC_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -598,7 +595,8 @@ void tfm_spm_init(void)
|
||||||
}
|
}
|
||||||
g_spm_ipc_partition[i].index = i;
|
g_spm_ipc_partition[i].index = i;
|
||||||
g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
|
g_spm_ipc_partition[i].id = tfm_spm_partition_get_partition_id(i);
|
||||||
tfm_event_init(&g_spm_ipc_partition[i].signal_event, EVENT_STAT_WAITED);
|
|
||||||
|
tfm_event_init(&g_spm_ipc_partition[i].signal_evnt);
|
||||||
tfm_list_init(&g_spm_ipc_partition[i].service_list);
|
tfm_list_init(&g_spm_ipc_partition[i].service_list);
|
||||||
|
|
||||||
pth = tfm_spm_partition_get_thread_info_ext(i);
|
pth = tfm_spm_partition_get_thread_info_ext(i);
|
||||||
|
|
|
@ -18,9 +18,9 @@
|
||||||
#include "tfm_internal_defines.h"
|
#include "tfm_internal_defines.h"
|
||||||
#include "tfm_message_queue.h"
|
#include "tfm_message_queue.h"
|
||||||
#include "tfm_spm.h"
|
#include "tfm_spm.h"
|
||||||
#include "secure_utilities.h"
|
|
||||||
#include "tfm_api.h"
|
#include "tfm_api.h"
|
||||||
#include "tfm_secure_api.h"
|
#include "tfm_secure_api.h"
|
||||||
|
#include "tfm_memory_utils.h"
|
||||||
|
|
||||||
#define PSA_TIMEOUT_MASK PSA_BLOCK
|
#define PSA_TIMEOUT_MASK PSA_BLOCK
|
||||||
|
|
||||||
|
@ -124,17 +124,25 @@ psa_status_t tfm_svcall_psa_call(uint32_t *args, int32_t ns_caller, uint32_t lr)
|
||||||
in_num = (size_t)args[2];
|
in_num = (size_t)args[2];
|
||||||
outptr = (psa_outvec *)args[3];
|
outptr = (psa_outvec *)args[3];
|
||||||
/*
|
/*
|
||||||
* 5th parameter is pushed at stack top before SVC; plus exception stacked contents,
|
* 5th parameter is pushed at stack top before SVC, then PE hardware
|
||||||
* 5th parameter is now at 8th position in SVC handler.
|
* stacks the execution context. The size of the context depends on
|
||||||
* However, if thread mode applies FloatPoint, then FloatPoint context is pushed into
|
* various settings:
|
||||||
* stack and then 5th parameter will be args[26].
|
* - if FP is not used, 5th parameter is at 8th position counting
|
||||||
|
* from SP;
|
||||||
|
* - if FP is used and FPCCR_S.TS is 0, 5th parameter is at 26th
|
||||||
|
* position counting from SP;
|
||||||
|
* - if FP is used and FPCCR_S.TS is 1, 5th parameter is at 42th
|
||||||
|
* position counting from SP.
|
||||||
*/
|
*/
|
||||||
if (lr & EXC_RETURN_FPU_FRAME_BASIC) {
|
if (lr & EXC_RETURN_FPU_FRAME_BASIC) {
|
||||||
out_num = (size_t)args[8];
|
out_num = (size_t)args[8];
|
||||||
}
|
#if defined (__FPU_USED) && (__FPU_USED == 1U)
|
||||||
else {
|
} else if (FPU->FPCCR & FPU_FPCCR_TS_Msk) {
|
||||||
|
out_num = (size_t)args[42];
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
out_num = (size_t)args[26];
|
out_num = (size_t)args[26];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* FixMe: From non-secure caller, vec and len are composed into a new
|
* FixMe: From non-secure caller, vec and len are composed into a new
|
||||||
|
@ -307,8 +315,8 @@ static psa_signal_t tfm_svcall_psa_wait(uint32_t *args)
|
||||||
* runtime context. After new signal(s) are available, the return value
|
* runtime context. After new signal(s) are available, the return value
|
||||||
* is updated with the available signal(s) and blocked thread gets to run.
|
* is updated with the available signal(s) and blocked thread gets to run.
|
||||||
*/
|
*/
|
||||||
if ((timeout == PSA_BLOCK) && ((partition->signals & signal_mask) == 0)) {
|
if (timeout == PSA_BLOCK && (partition->signals & signal_mask) == 0) {
|
||||||
tfm_event_wait(&partition->signal_event);
|
tfm_event_wait(&partition->signal_evnt);
|
||||||
}
|
}
|
||||||
|
|
||||||
return partition->signals & signal_mask;
|
return partition->signals & signal_mask;
|
||||||
|
@ -683,7 +691,7 @@ static void update_caller_outvec_len(struct tfm_msg_body_t *msg)
|
||||||
* FixeMe: abstract these part into dedicated functions to avoid
|
* FixeMe: abstract these part into dedicated functions to avoid
|
||||||
* accessing thread context in psa layer
|
* accessing thread context in psa layer
|
||||||
*/
|
*/
|
||||||
TFM_ASSERT(msg->ack_mtx.owner->status == THRD_STAT_BLOCK);
|
TFM_ASSERT(msg->ack_evnt.owner->status == THRD_STAT_BLOCK);
|
||||||
|
|
||||||
while (msg->msg.out_size[i] != 0) {
|
while (msg->msg.out_size[i] != 0) {
|
||||||
TFM_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
|
TFM_ASSERT(msg->caller_outvec[i].base == msg->outvec[i].base);
|
||||||
|
@ -800,11 +808,7 @@ static void tfm_svcall_psa_reply(uint32_t *args)
|
||||||
tfm_panic();
|
tfm_panic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Save return value for blocked threads */
|
tfm_event_wake(&msg->ack_evnt, ret);
|
||||||
tfm_event_owner_retval(&msg->ack_mtx, ret);
|
|
||||||
|
|
||||||
/* Wake waiting thread up */
|
|
||||||
tfm_event_signal(&msg->ack_mtx);
|
|
||||||
|
|
||||||
/* Message should not be unsed anymore */
|
/* Message should not be unsed anymore */
|
||||||
tfm_spm_free_msg(msg);
|
tfm_spm_free_msg(msg);
|
||||||
|
@ -852,11 +856,8 @@ static void tfm_svcall_psa_notify(uint32_t *args)
|
||||||
* called psa_wait(). Set the return value with the available signals
|
* called psa_wait(). Set the return value with the available signals
|
||||||
* before wake it up with tfm_event_signal().
|
* before wake it up with tfm_event_signal().
|
||||||
*/
|
*/
|
||||||
tfm_event_owner_retval(&partition->signal_event,
|
tfm_event_wake(&partition->signal_evnt,
|
||||||
partition->signals & partition->signal_mask);
|
partition->signals & partition->signal_mask);
|
||||||
|
|
||||||
/* Wake waiting thread up */
|
|
||||||
tfm_event_signal(&partition->signal_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include "tfm_arch_v8m.h"
|
#include "tfm_arch_v8m.h"
|
||||||
#include "tfm_thread.h"
|
#include "tfm_thread.h"
|
||||||
#include "tfm_utils.h"
|
#include "tfm_utils.h"
|
||||||
#include "secure_utilities.h"
|
#include "tfm_memory_utils.h"
|
||||||
|
|
||||||
/* Force ZERO in case ZI(bss) clear is missing */
|
/* Force ZERO in case ZI(bss) clear is missing */
|
||||||
static struct tfm_thrd_ctx *p_thrd_head = NULL;
|
static struct tfm_thrd_ctx *p_thrd_head = NULL;
|
||||||
|
|
|
@ -4,59 +4,27 @@
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#include <inttypes.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "tfm_arch_v8m.h"
|
|
||||||
#include "tfm_thread.h"
|
#include "tfm_thread.h"
|
||||||
#include "tfm_utils.h"
|
#include "tfm_utils.h"
|
||||||
#include "tfm_wait.h"
|
#include "tfm_wait.h"
|
||||||
|
|
||||||
void tfm_event_wait(struct tfm_event_ctx *pevt)
|
void tfm_event_wait(struct tfm_event_t *pevnt)
|
||||||
{
|
{
|
||||||
struct tfm_thrd_ctx *curr_thrd = tfm_thrd_curr_thread();
|
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
|
||||||
|
|
||||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
pevnt->owner = tfm_thrd_curr_thread();
|
||||||
|
tfm_thrd_set_status(pevnt->owner, THRD_STAT_BLOCK);
|
||||||
if (pevt->status == EVENT_STAT_WAITED) {
|
tfm_thrd_activate_schedule();
|
||||||
pevt->owner = curr_thrd;
|
|
||||||
pevt->retval = TFM_STATE_1ST_ARG(&pevt->owner->state_ctx);
|
|
||||||
tfm_thrd_set_status(pevt->owner, THRD_STAT_BLOCK);
|
|
||||||
tfm_thrd_activate_schedule();
|
|
||||||
}
|
|
||||||
|
|
||||||
pevt->status = EVENT_STAT_WAITED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Peek the status to see if caller would block. */
|
void tfm_event_wake(struct tfm_event_t *pevnt, uint32_t retval)
|
||||||
uint32_t tfm_event_peek(struct tfm_event_ctx *pevt)
|
|
||||||
{
|
{
|
||||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
TFM_ASSERT(pevnt && pevnt->magic == TFM_EVENT_MAGIC);
|
||||||
|
|
||||||
return pevt->status;
|
if (pevnt->owner && pevnt->owner->status == THRD_STAT_BLOCK) {
|
||||||
}
|
tfm_thrd_set_status(pevnt->owner, THRD_STAT_RUNNING);
|
||||||
|
tfm_thrd_set_retval(pevnt->owner, retval);
|
||||||
void tfm_event_signal(struct tfm_event_ctx *pevt)
|
|
||||||
{
|
|
||||||
TFM_ASSERT(pevt && pevt->magic == EVENT_MAGIC);
|
|
||||||
|
|
||||||
pevt->status = EVENT_STAT_SIGNALED;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Wake the blocked owner up and keep the status as EVENT_STAT_WAITED
|
|
||||||
* if there is an owner. Or the second event wait caller will return
|
|
||||||
* without block since status is EVENT_STAT_SIGNALED.
|
|
||||||
*/
|
|
||||||
if (pevt->owner && pevt->owner->status == THRD_STAT_BLOCK) {
|
|
||||||
tfm_thrd_set_status(pevt->owner, THRD_STAT_RUNNING);
|
|
||||||
tfm_thrd_set_retval(pevt->owner, pevt->retval);
|
|
||||||
pevt->status = EVENT_STAT_WAITED;
|
|
||||||
tfm_thrd_activate_schedule();
|
tfm_thrd_activate_schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tfm_event_owner_retval(struct tfm_event_ctx *pmtx, uint32_t retval)
|
|
||||||
{
|
|
||||||
TFM_ASSERT(pmtx && pmtx->magic == EVENT_MAGIC);
|
|
||||||
|
|
||||||
pmtx->retval = retval;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
|
@ -8,9 +8,9 @@
|
||||||
#ifndef __SECURE_UTILITIES_H__
|
#ifndef __SECURE_UTILITIES_H__
|
||||||
#define __SECURE_UTILITIES_H__
|
#define __SECURE_UTILITIES_H__
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
#include "cmsis_compiler.h"
|
#include "cmsis_compiler.h"
|
||||||
#include "tfm_svc.h"
|
#include "tfm_svc.h"
|
||||||
#include "string.h"
|
|
||||||
|
|
||||||
#define EXC_RETURN_INDICATOR (0xF << 28)
|
#define EXC_RETURN_INDICATOR (0xF << 28)
|
||||||
#define EXC_RETURN_SECURITY_STACK_STATUS_MASK (0x3 << 5)
|
#define EXC_RETURN_SECURITY_STACK_STATUS_MASK (0x3 << 5)
|
||||||
|
@ -106,27 +106,4 @@ __STATIC_INLINE void __set_CONTROL_SPSEL(int32_t SPSEL)
|
||||||
__asm("ISB");
|
__asm("ISB");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: The following functions are wrappers around standard C library
|
|
||||||
* functions: memcpy, memcmp, memset
|
|
||||||
* In long term standard C library might be removed from TF-M project or
|
|
||||||
* replaced with a secure implementation due to security concerns.
|
|
||||||
*/
|
|
||||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
|
||||||
void tfm_memcpy(void *dest, const void *src, uint32_t size)
|
|
||||||
{
|
|
||||||
memcpy(dest, src, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
|
||||||
int32_t tfm_memcmp(const void * ptr1, const void * ptr2, size_t num)
|
|
||||||
{
|
|
||||||
return (memcmp(ptr1, ptr2, num));
|
|
||||||
}
|
|
||||||
|
|
||||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
|
||||||
void * tfm_memset(void * ptr, int value, size_t num)
|
|
||||||
{
|
|
||||||
return (memset(ptr, value, num));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* __SECURE_UTILITIES_H__ */
|
#endif /* __SECURE_UTILITIES_H__ */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "bl2/include/tfm_boot_status.h"
|
#include "bl2/include/tfm_boot_status.h"
|
||||||
#include "secure_utilities.h"
|
#include "tfm_memory_utils.h"
|
||||||
#include "tfm_internal.h"
|
#include "tfm_internal.h"
|
||||||
#include "tfm_api.h"
|
#include "tfm_api.h"
|
||||||
#include "flash_layout.h"
|
#include "flash_layout.h"
|
||||||
|
@ -57,13 +57,13 @@ void tfm_core_validate_boot_data(void)
|
||||||
void tfm_core_get_boot_data_handler(uint32_t args[])
|
void tfm_core_get_boot_data_handler(uint32_t args[])
|
||||||
{
|
{
|
||||||
uint8_t tlv_major = (uint8_t)args[0];
|
uint8_t tlv_major = (uint8_t)args[0];
|
||||||
uint8_t *ptr = (uint8_t *)args[1];
|
uint8_t *buf_start = (uint8_t *)args[1];
|
||||||
uint16_t buf_size = (uint16_t)args[2];
|
uint16_t buf_size = (uint16_t)args[2];
|
||||||
uint8_t *buf_start = ptr;
|
uint8_t *ptr;
|
||||||
uint32_t running_partition_idx =
|
uint32_t running_partition_idx =
|
||||||
tfm_spm_partition_get_running_partition_idx();
|
tfm_spm_partition_get_running_partition_idx();
|
||||||
struct shared_data_tlv_header *tlv_header;
|
struct shared_data_tlv_header *tlv_header;
|
||||||
struct shared_data_tlv_entry *tlv_entry;
|
struct shared_data_tlv_entry tlv_entry;
|
||||||
uintptr_t tlv_end, offset;
|
uintptr_t tlv_end, offset;
|
||||||
uint32_t res;
|
uint32_t res;
|
||||||
|
|
||||||
|
@ -71,9 +71,9 @@ void tfm_core_get_boot_data_handler(uint32_t args[])
|
||||||
* by the partition
|
* by the partition
|
||||||
*/
|
*/
|
||||||
res = tfm_core_check_buffer_access(running_partition_idx,
|
res = tfm_core_check_buffer_access(running_partition_idx,
|
||||||
(void*)buf_start,
|
(void *)buf_start,
|
||||||
buf_size,
|
buf_size,
|
||||||
2);
|
2); /* Check 4 bytes alignment */
|
||||||
if (!res) {
|
if (!res) {
|
||||||
/* Not in accessible range, return error */
|
/* Not in accessible range, return error */
|
||||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
@ -97,26 +97,31 @@ void tfm_core_get_boot_data_handler(uint32_t args[])
|
||||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
tfm_memcpy(ptr, tlv_header, SHARED_DATA_HEADER_SIZE);
|
tlv_header = (struct shared_data_tlv_header *)buf_start;
|
||||||
ptr += SHARED_DATA_HEADER_SIZE;
|
tlv_header->tlv_magic = SHARED_DATA_TLV_INFO_MAGIC;
|
||||||
|
tlv_header->tlv_tot_len = SHARED_DATA_HEADER_SIZE;
|
||||||
|
ptr = (uint8_t *)tlv_header + SHARED_DATA_HEADER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Iterates over the TLV section and copy TLVs with requested major
|
/* Iterates over the TLV section and copy TLVs with requested major
|
||||||
* type to the provided buffer.
|
* type to the provided buffer.
|
||||||
*/
|
*/
|
||||||
for(; offset < tlv_end; offset += tlv_entry->tlv_len) {
|
for (; offset < tlv_end; offset += tlv_entry.tlv_len) {
|
||||||
tlv_entry = (struct shared_data_tlv_entry *)offset;
|
/* Create local copy to avoid unaligned access */
|
||||||
if (tlv_entry->tlv_major_type == tlv_major) {
|
tfm_memcpy(&tlv_entry,
|
||||||
|
(const void *)offset,
|
||||||
|
SHARED_DATA_ENTRY_HEADER_SIZE);
|
||||||
|
if (GET_MAJOR(tlv_entry.tlv_type) == tlv_major) {
|
||||||
/* Check buffer overflow */
|
/* Check buffer overflow */
|
||||||
if ((ptr - buf_start + tlv_entry->tlv_len) > buf_size) {
|
if ((ptr - buf_start + tlv_entry.tlv_len) > buf_size) {
|
||||||
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
args[0] = TFM_ERROR_INVALID_PARAMETER;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tfm_memcpy(ptr, (const void *)tlv_entry, tlv_entry->tlv_len);
|
tfm_memcpy(ptr, (const void *)offset, tlv_entry.tlv_len);
|
||||||
|
|
||||||
ptr += tlv_entry->tlv_len;
|
ptr += tlv_entry.tlv_len;
|
||||||
tlv_header->tlv_tot_len += tlv_entry->tlv_len;
|
tlv_header->tlv_tot_len += tlv_entry.tlv_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
args[0] = TFM_SUCCESS;
|
args[0] = TFM_SUCCESS;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
* Copyright (c) 2017-2019, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
|
@ -8,7 +8,6 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "cmsis.h"
|
|
||||||
#include "secure_utilities.h"
|
#include "secure_utilities.h"
|
||||||
#include "arm_acle.h"
|
#include "arm_acle.h"
|
||||||
#include "tfm_svc.h"
|
#include "tfm_svc.h"
|
||||||
|
@ -16,6 +15,7 @@
|
||||||
#include "region_defs.h"
|
#include "region_defs.h"
|
||||||
#include "tfm_api.h"
|
#include "tfm_api.h"
|
||||||
#include "tfm_internal.h"
|
#include "tfm_internal.h"
|
||||||
|
#include "tfm_memory_utils.h"
|
||||||
#ifdef TFM_PSA_API
|
#ifdef TFM_PSA_API
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "tfm_svcalls.h"
|
#include "tfm_svcalls.h"
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TFM_MEMORY_UTILS_H__
|
||||||
|
#define __TFM_MEMORY_UTILS_H__
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "cmsis_compiler.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* FIXME: The following functions are wrappers around standard C library
|
||||||
|
* functions: memcpy, memcmp, memset
|
||||||
|
* In long term standard C library might be removed from TF-M project or
|
||||||
|
* replaced with a secure implementation due to security concerns.
|
||||||
|
*/
|
||||||
|
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||||
|
void *tfm_memcpy(void *dest, const void *src, size_t num)
|
||||||
|
{
|
||||||
|
return (memcpy(dest, src, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||||
|
int tfm_memcmp(const void *ptr1, const void *ptr2, size_t num)
|
||||||
|
{
|
||||||
|
return (memcmp(ptr1, ptr2, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||||
|
void *tfm_memset(void *ptr, int value, size_t num)
|
||||||
|
{
|
||||||
|
return (memset(ptr, value, num));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* __TFM_MEMORY_UTILS_H__ */
|
|
@ -8,7 +8,7 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include "cmsis.h"
|
#include <arm_cmse.h>
|
||||||
#include "tfm_secure_api.h"
|
#include "tfm_secure_api.h"
|
||||||
#include "tfm_nspm.h"
|
#include "tfm_nspm.h"
|
||||||
#include "secure_utilities.h"
|
#include "secure_utilities.h"
|
||||||
|
@ -22,12 +22,15 @@
|
||||||
#error TFM_LVL is not defined!
|
#error TFM_LVL is not defined!
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if TFM_LVL == 1
|
|
||||||
/* Macros to pick linker symbols and allow references to sections */
|
/* Macros to pick linker symbols and allow references to sections */
|
||||||
#define REGION(a, b, c) a##b##c
|
#define REGION(a, b, c) a##b##c
|
||||||
#define REGION_NAME(a, b, c) REGION(a, b, c)
|
#define REGION_NAME(a, b, c) REGION(a, b, c)
|
||||||
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
#define REGION_DECLARE(a, b, c) extern uint32_t REGION_NAME(a, b, c)
|
||||||
|
|
||||||
|
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||||
|
REGION_DECLARE(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
|
||||||
|
|
||||||
|
#if TFM_LVL == 1
|
||||||
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||||
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,6 +41,15 @@ REGION_DECLARE(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
||||||
int32_t tfm_secure_lock;
|
int32_t tfm_secure_lock;
|
||||||
static int32_t tfm_secure_api_initializing = 1;
|
static int32_t tfm_secure_api_initializing = 1;
|
||||||
|
|
||||||
|
static int32_t is_iovec_api_call(void)
|
||||||
|
{
|
||||||
|
uint32_t current_partition_idx =
|
||||||
|
tfm_spm_partition_get_running_partition_idx();
|
||||||
|
const struct spm_partition_runtime_data_t *curr_part_data =
|
||||||
|
tfm_spm_partition_get_runtime_data(current_partition_idx);
|
||||||
|
return curr_part_data->iovec_api;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t *prepare_partition_ctx(
|
static int32_t *prepare_partition_ctx(
|
||||||
struct tfm_exc_stack_t *svc_ctx,
|
struct tfm_exc_stack_t *svc_ctx,
|
||||||
struct tfm_sfn_req_s *desc_ptr,
|
struct tfm_sfn_req_s *desc_ptr,
|
||||||
|
@ -62,6 +74,30 @@ static int32_t *prepare_partition_ctx(
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t *prepare_partition_iovec_ctx(
|
||||||
|
struct tfm_exc_stack_t *svc_ctx,
|
||||||
|
struct tfm_sfn_req_s *desc_ptr,
|
||||||
|
struct iovec_args_t *iovec_args,
|
||||||
|
int32_t *dst)
|
||||||
|
{
|
||||||
|
/* XPSR = as was when called, but make sure it's thread mode */
|
||||||
|
*(--dst) = svc_ctx->XPSR & 0xFFFFFE00;
|
||||||
|
/* ReturnAddress = resume veneer in new context */
|
||||||
|
*(--dst) = svc_ctx->RetAddr;
|
||||||
|
/* LR = sfn address */
|
||||||
|
*(--dst) = (int32_t)desc_ptr->sfn;
|
||||||
|
/* R12 = don't care */
|
||||||
|
*(--dst) = 0;
|
||||||
|
|
||||||
|
/* R0-R3 = sfn arguments */
|
||||||
|
*(--dst) = iovec_args->out_len;
|
||||||
|
*(--dst) = (uint32_t)iovec_args->out_vec;
|
||||||
|
*(--dst) = iovec_args->in_len;
|
||||||
|
*(--dst) = (uint32_t)iovec_args->in_vec;
|
||||||
|
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
static void restore_caller_ctx(
|
static void restore_caller_ctx(
|
||||||
struct tfm_exc_stack_t *svc_ctx,
|
struct tfm_exc_stack_t *svc_ctx,
|
||||||
struct tfm_exc_stack_t *target_ctx)
|
struct tfm_exc_stack_t *target_ctx)
|
||||||
|
@ -75,6 +111,241 @@ static void restore_caller_ctx(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check whether a memory range is inside a memory region.
|
||||||
|
*
|
||||||
|
* \param[in] p The start address of the range to check
|
||||||
|
* \param[in] s The size of the range to check
|
||||||
|
* \param[in] region_start The start address of the region, which should
|
||||||
|
* contain the range
|
||||||
|
* \param[in] region_len The size of the region, which should contain the
|
||||||
|
* range
|
||||||
|
*
|
||||||
|
* \return 1 if the region contains the range, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t check_address_range(const void *p, size_t s,
|
||||||
|
uintptr_t region_start, uint32_t region_len)
|
||||||
|
{
|
||||||
|
int32_t range_in_region = 0;
|
||||||
|
|
||||||
|
/* Check for overflow in the range parameters */
|
||||||
|
if ((uintptr_t)p > UINTPTR_MAX-s) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We trust the region parameters, and don't check for overflow */
|
||||||
|
|
||||||
|
/* Calculate the result */
|
||||||
|
range_in_region = ((uintptr_t)p >= region_start) &&
|
||||||
|
((uintptr_t)p+s <= region_start+region_len);
|
||||||
|
|
||||||
|
return range_in_region;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check whether the current partition has access to a memory range
|
||||||
|
*
|
||||||
|
* This function assumes, that the current MPU configuration is set for the
|
||||||
|
* partition to be checked. The flags should contain information of the
|
||||||
|
* execution mode of the partition code (priv/unpriv), and access type
|
||||||
|
* (read/write) as specified in "ARMv8-M Security Extensions: Requirements on
|
||||||
|
* Development Tools" chapter "Address range check intrinsic"
|
||||||
|
*
|
||||||
|
* \param[in] p The start address of the range to check
|
||||||
|
* \param[in] s The size of the range to check
|
||||||
|
* \param[in] flags The flags to pass to the cmse_check_address_range func
|
||||||
|
*
|
||||||
|
* \return 1 if the partition has access to the memory range, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t has_access_to_region(const void *p, size_t s, uint32_t flags)
|
||||||
|
{
|
||||||
|
int32_t range_access_allowed_by_mpu;
|
||||||
|
|
||||||
|
uint32_t scratch_base =
|
||||||
|
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Base);
|
||||||
|
uint32_t scratch_limit =
|
||||||
|
(uint32_t)®ION_NAME(Image$$, TFM_UNPRIV_SCRATCH, $$ZI$$Limit);
|
||||||
|
|
||||||
|
/* Use the TT instruction to check access to the partition's regions*/
|
||||||
|
range_access_allowed_by_mpu =
|
||||||
|
cmse_check_address_range((void *)p, s, flags) != NULL;
|
||||||
|
|
||||||
|
if (range_access_allowed_by_mpu) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the check for the current MPU settings fails, check for the share
|
||||||
|
* region, only if the partition is secure
|
||||||
|
*/
|
||||||
|
if ((flags & CMSE_NONSECURE) == 0) {
|
||||||
|
if (check_address_range(p, s, scratch_base,
|
||||||
|
scratch_limit+1-scratch_base)) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If all else fails, check whether the region is in the non-secure
|
||||||
|
* memory
|
||||||
|
*/
|
||||||
|
return
|
||||||
|
check_address_range(p, s, NS_CODE_START, NS_CODE_LIMIT+1-NS_CODE_START) ||
|
||||||
|
check_address_range(p, s, NS_DATA_START, NS_DATA_LIMIT+1-NS_DATA_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check whether the current partition has read access to a memory range
|
||||||
|
*
|
||||||
|
* This function assumes, that the current MPU configuration is set for the
|
||||||
|
* partition to be checked.
|
||||||
|
*
|
||||||
|
* \param[in] p The start address of the range to check
|
||||||
|
* \param[in] s The size of the range to check
|
||||||
|
* \param[in] ns_caller Whether the current partition is a non-secure one
|
||||||
|
*
|
||||||
|
* \return 1 if the partition has access to the memory range, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t has_read_access_to_region(const void *p, size_t s,
|
||||||
|
int32_t ns_caller)
|
||||||
|
{
|
||||||
|
uint32_t flags = CMSE_MPU_UNPRIV|CMSE_MPU_READ;
|
||||||
|
|
||||||
|
if (ns_caller) {
|
||||||
|
flags |= CMSE_NONSECURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_access_to_region(p, s, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Check whether the current partition has write access to a memory range
|
||||||
|
*
|
||||||
|
* This function assumes, that the current MPU configuration is set for the
|
||||||
|
* partition to be checked.
|
||||||
|
*
|
||||||
|
* \param[in] p The start address of the range to check
|
||||||
|
* \param[in] s The size of the range to check
|
||||||
|
* \param[in] ns_caller Whether the current partition is a non-secure one
|
||||||
|
*
|
||||||
|
* \return 1 if the partition has access to the memory range, 0 otherwise.
|
||||||
|
*/
|
||||||
|
static int32_t has_write_access_to_region(void *p, size_t s, int32_t ns_caller)
|
||||||
|
{
|
||||||
|
uint32_t flags = CMSE_MPU_UNPRIV|CMSE_MPU_READWRITE;
|
||||||
|
|
||||||
|
if (ns_caller) {
|
||||||
|
flags |= CMSE_NONSECURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return has_access_to_region(p, s, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Check whether the iovec parameters are valid, and the memory ranges
|
||||||
|
* are in the posession of the calling partition
|
||||||
|
*
|
||||||
|
* \param[in] desc_ptr The secure function request descriptor
|
||||||
|
*
|
||||||
|
* \return Return /ref TFM_SUCCESS if the iovec parameters are valid, error code
|
||||||
|
* otherwise as in /ref tfm_status_e
|
||||||
|
*/
|
||||||
|
static int32_t tfm_core_check_sfn_parameters(struct tfm_sfn_req_s *desc_ptr)
|
||||||
|
{
|
||||||
|
struct psa_invec *in_vec = (psa_invec *)desc_ptr->args[0];
|
||||||
|
size_t in_len = desc_ptr->args[1];
|
||||||
|
struct psa_outvec *out_vec = (psa_outvec *)desc_ptr->args[2];
|
||||||
|
size_t out_len = desc_ptr->args[3];
|
||||||
|
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
/* The number of vectors are within range. Extra checks to avoid overflow */
|
||||||
|
if ((in_len > PSA_MAX_IOVEC) || (out_len > PSA_MAX_IOVEC) ||
|
||||||
|
(in_len + out_len > PSA_MAX_IOVEC)) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether the caller partition has at write access to the iovec
|
||||||
|
* structures themselves. Use the TT instruction for this.
|
||||||
|
*/
|
||||||
|
if (in_len > 0) {
|
||||||
|
if ((in_vec == NULL) ||
|
||||||
|
(has_write_access_to_region(in_vec, sizeof(psa_invec)*in_len,
|
||||||
|
desc_ptr->ns_caller) != 1)) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_vec != NULL) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (out_len > 0) {
|
||||||
|
if ((out_vec == NULL) ||
|
||||||
|
(has_write_access_to_region(out_vec, sizeof(psa_outvec)*out_len,
|
||||||
|
desc_ptr->ns_caller) != 1)) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (out_vec != NULL) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether the caller partition has access to the data inside the
|
||||||
|
* iovecs
|
||||||
|
*/
|
||||||
|
for (i = 0; i < in_len; ++i) {
|
||||||
|
if (in_vec[i].len > 0) {
|
||||||
|
if ((in_vec[i].base == NULL) ||
|
||||||
|
(has_read_access_to_region(in_vec[i].base, in_vec[i].len,
|
||||||
|
desc_ptr->ns_caller) != 1)) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (i = 0; i < out_len; ++i) {
|
||||||
|
if (out_vec[i].len > 0) {
|
||||||
|
if ((out_vec[i].base == NULL) ||
|
||||||
|
(has_write_access_to_region(out_vec[i].base, out_vec[i].len,
|
||||||
|
desc_ptr->ns_caller) != 1)) {
|
||||||
|
return TFM_ERROR_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TFM_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tfm_copy_iovec_parameters(struct iovec_args_t *target,
|
||||||
|
const struct iovec_args_t *source)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
target->in_len = source->in_len;
|
||||||
|
for (i = 0; i < source->in_len; ++i) {
|
||||||
|
target->in_vec[i].base = source->in_vec[i].base;
|
||||||
|
target->in_vec[i].len = source->in_vec[i].len;
|
||||||
|
}
|
||||||
|
target->out_len = source->out_len;
|
||||||
|
for (i = 0; i < source->out_len; ++i) {
|
||||||
|
target->out_vec[i].base = source->out_vec[i].base;
|
||||||
|
target->out_vec[i].len = source->out_vec[i].len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tfm_clear_iovec_parameters(struct iovec_args_t *args)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
args->in_len = 0;
|
||||||
|
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
|
||||||
|
args->in_vec[i].base = NULL;
|
||||||
|
args->in_vec[i].len = 0;
|
||||||
|
}
|
||||||
|
args->out_len = 0;
|
||||||
|
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
|
||||||
|
args->out_vec[i].base = NULL;
|
||||||
|
args->out_vec[i].len = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
||||||
uint32_t excReturn)
|
uint32_t excReturn)
|
||||||
{
|
{
|
||||||
|
@ -89,6 +360,7 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
||||||
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
||||||
uint32_t caller_partition_id;
|
uint32_t caller_partition_id;
|
||||||
int32_t client_id;
|
int32_t client_id;
|
||||||
|
struct iovec_args_t *iovec_args;
|
||||||
|
|
||||||
caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
|
caller_flags = tfm_spm_partition_get_flags(caller_partition_idx);
|
||||||
|
|
||||||
|
@ -145,8 +417,13 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
||||||
|
|
||||||
#if TFM_LVL == 1
|
#if TFM_LVL == 1
|
||||||
/* Prepare switch to shared secure partition stack */
|
/* Prepare switch to shared secure partition stack */
|
||||||
|
/* In case the call is coming from the non-secure world, we save the iovecs
|
||||||
|
* on the stop of the stack. So the memory area, that can actually be used
|
||||||
|
* as stack by the partitions starts at a lower address
|
||||||
|
*/
|
||||||
partition_psp =
|
partition_psp =
|
||||||
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit);
|
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
|
||||||
|
sizeof(struct iovec_args_t);
|
||||||
partition_psplim =
|
partition_psplim =
|
||||||
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
(uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Base);
|
||||||
#else
|
#else
|
||||||
|
@ -193,16 +470,53 @@ static int32_t tfm_start_partition(struct tfm_sfn_req_s *desc_ptr,
|
||||||
* handler mode
|
* handler mode
|
||||||
*/
|
*/
|
||||||
if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
|
if ((desc_ptr->ns_caller) || (tfm_secure_api_initializing)) {
|
||||||
/* Prepare the partition context, update stack ptr */
|
if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
|
||||||
psp = (uint32_t)prepare_partition_ctx(
|
/* Save the iovecs on the common stack. The vectors had been sanity
|
||||||
svc_ctx, desc_ptr, (int32_t *)partition_psp);
|
* checked already, and since then the interrupts have been kept
|
||||||
|
* disabled. So we can be sure that the vectors haven't been
|
||||||
|
* tampered with since the check.
|
||||||
|
*/
|
||||||
|
iovec_args = (struct iovec_args_t *)
|
||||||
|
((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
|
||||||
|
sizeof(struct iovec_args_t));
|
||||||
|
tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args);
|
||||||
|
tfm_copy_iovec_parameters(iovec_args,
|
||||||
|
&(curr_part_data->iovec_args));
|
||||||
|
|
||||||
|
/* Prepare the partition context, update stack ptr */
|
||||||
|
psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
|
||||||
|
iovec_args,
|
||||||
|
(int32_t *)partition_psp);
|
||||||
|
} else {
|
||||||
|
/* Prepare the partition context, update stack ptr */
|
||||||
|
psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
|
||||||
|
(int32_t *)partition_psp);
|
||||||
|
}
|
||||||
__set_PSP(psp);
|
__set_PSP(psp);
|
||||||
__set_PSPLIM(partition_psplim);
|
__set_PSPLIM(partition_psplim);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Prepare the partition context, update stack ptr */
|
if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
|
||||||
psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
|
/* Save the iovecs on the stack of the partition. The vectors had been
|
||||||
(int32_t *)partition_psp);
|
* sanity checked already, and since then the interrupts have been kept
|
||||||
|
* disabled. So we can be sure that the vectors haven't been tampered
|
||||||
|
* with since the check.
|
||||||
|
*/
|
||||||
|
iovec_args =
|
||||||
|
(struct iovec_args_t *)(tfm_spm_partition_get_stack_top(partition_idx) -
|
||||||
|
sizeof(struct iovec_args_t));
|
||||||
|
tfm_spm_partition_set_iovec(partition_idx, desc_ptr->args);
|
||||||
|
tfm_copy_iovec_parameters(iovec_args, &(curr_part_data->iovec_args));
|
||||||
|
|
||||||
|
/* Prepare the partition context, update stack ptr */
|
||||||
|
psp = (uint32_t)prepare_partition_iovec_ctx(svc_ctx, desc_ptr,
|
||||||
|
iovec_args,
|
||||||
|
(int32_t *)partition_psp);
|
||||||
|
} else {
|
||||||
|
/* Prepare the partition context, update stack ptr */
|
||||||
|
psp = (uint32_t)prepare_partition_ctx(svc_ctx, desc_ptr,
|
||||||
|
(int32_t *)partition_psp);
|
||||||
|
}
|
||||||
__set_PSP(psp);
|
__set_PSP(psp);
|
||||||
__set_PSPLIM(partition_psplim);
|
__set_PSPLIM(partition_psplim);
|
||||||
#endif
|
#endif
|
||||||
|
@ -224,7 +538,9 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn)
|
||||||
uint32_t return_partition_idx;
|
uint32_t return_partition_idx;
|
||||||
uint32_t return_partition_flags;
|
uint32_t return_partition_flags;
|
||||||
uint32_t psp = __get_PSP();
|
uint32_t psp = __get_PSP();
|
||||||
|
int i;
|
||||||
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
struct tfm_exc_stack_t *svc_ctx = (struct tfm_exc_stack_t *)psp;
|
||||||
|
struct iovec_args_t *iovec_args;
|
||||||
|
|
||||||
if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
|
if (current_partition_idx == SPM_INVALID_PARTITION_IDX) {
|
||||||
return TFM_SECURE_UNLOCK_FAILED;
|
return TFM_SECURE_UNLOCK_FAILED;
|
||||||
|
@ -304,6 +620,18 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn)
|
||||||
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
|
uint32_t psp_stack_bottom = (uint32_t)Image$$ARM_LIB_STACK$$ZI$$Base;
|
||||||
__set_PSPLIM(psp_stack_bottom);
|
__set_PSPLIM(psp_stack_bottom);
|
||||||
|
|
||||||
|
/* FIXME: The condition should be removed once all the secure service
|
||||||
|
* calls are done via the iovec veneers */
|
||||||
|
if (curr_part_data->iovec_api) {
|
||||||
|
iovec_args = (struct iovec_args_t *)
|
||||||
|
((uint32_t)®ION_NAME(Image$$, TFM_SECURE_STACK, $$ZI$$Limit)-
|
||||||
|
sizeof(struct iovec_args_t));
|
||||||
|
|
||||||
|
for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
|
||||||
|
curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
|
||||||
|
}
|
||||||
|
tfm_clear_iovec_parameters(iovec_args);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
/* Restore caller context */
|
/* Restore caller context */
|
||||||
|
@ -314,7 +642,20 @@ static int32_t tfm_return_from_partition(uint32_t *excReturn)
|
||||||
__set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
|
__set_PSPLIM(tfm_spm_partition_get_stack_bottom(return_partition_idx));
|
||||||
/* Clear the context entry before returning */
|
/* Clear the context entry before returning */
|
||||||
tfm_spm_partition_set_stack(
|
tfm_spm_partition_set_stack(
|
||||||
current_partition_idx, psp - sizeof(struct tfm_exc_stack_t));
|
current_partition_idx, psp + sizeof(struct tfm_exc_stack_t));
|
||||||
|
|
||||||
|
/* FIXME: The condition should be removed once all the secure service
|
||||||
|
* calls are done via the iovec veneers */
|
||||||
|
if (curr_part_data->iovec_api) {
|
||||||
|
iovec_args = (struct iovec_args_t *)
|
||||||
|
(tfm_spm_partition_get_stack_top(current_partition_idx) -
|
||||||
|
sizeof(struct iovec_args_t));
|
||||||
|
|
||||||
|
for (i = 0; i < curr_part_data->iovec_args.out_len; ++i) {
|
||||||
|
curr_part_data->orig_outvec[i].len = iovec_args->out_vec[i].len;
|
||||||
|
}
|
||||||
|
tfm_clear_iovec_parameters(iovec_args);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
tfm_spm_partition_cleanup_context(current_partition_idx);
|
tfm_spm_partition_cleanup_context(current_partition_idx);
|
||||||
|
@ -396,12 +737,22 @@ int32_t tfm_core_sfn_request_handler(
|
||||||
res = tfm_check_sfn_req_integrity(desc_ptr);
|
res = tfm_check_sfn_req_integrity(desc_ptr);
|
||||||
if (res != TFM_SUCCESS) {
|
if (res != TFM_SUCCESS) {
|
||||||
ERROR_MSG("Invalid service request!");
|
ERROR_MSG("Invalid service request!");
|
||||||
return TFM_ERROR_STATUS(res);
|
tfm_secure_api_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
__disable_irq();
|
__disable_irq();
|
||||||
|
|
||||||
desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
|
desc_ptr->caller_part_idx = tfm_spm_partition_get_running_partition_idx();
|
||||||
|
|
||||||
|
if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
|
||||||
|
res = tfm_core_check_sfn_parameters(desc_ptr);
|
||||||
|
if (res != TFM_SUCCESS) {
|
||||||
|
/* The sanity check of iovecs failed. */
|
||||||
|
__enable_irq();
|
||||||
|
tfm_secure_api_error_handler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
res = tfm_core_check_sfn_req_rules(desc_ptr);
|
res = tfm_core_check_sfn_req_rules(desc_ptr);
|
||||||
if (res != TFM_SUCCESS) {
|
if (res != TFM_SUCCESS) {
|
||||||
/* FixMe: error compartmentalization TBD */
|
/* FixMe: error compartmentalization TBD */
|
||||||
|
@ -409,7 +760,7 @@ int32_t tfm_core_sfn_request_handler(
|
||||||
desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
|
desc_ptr->caller_part_idx, SPM_PARTITION_STATE_CLOSED);
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
ERROR_MSG("Unauthorized service request!");
|
ERROR_MSG("Unauthorized service request!");
|
||||||
return TFM_ERROR_STATUS(res);
|
tfm_secure_api_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
res = tfm_start_partition(desc_ptr, excReturn);
|
res = tfm_start_partition(desc_ptr, excReturn);
|
||||||
|
@ -417,7 +768,7 @@ int32_t tfm_core_sfn_request_handler(
|
||||||
/* FixMe: consider possible fault scenarios */
|
/* FixMe: consider possible fault scenarios */
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
ERROR_MSG("Failed to process service request!");
|
ERROR_MSG("Failed to process service request!");
|
||||||
return TFM_ERROR_STATUS(res);
|
tfm_secure_api_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
__enable_irq();
|
__enable_irq();
|
||||||
|
@ -432,6 +783,14 @@ int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr)
|
||||||
int32_t *args;
|
int32_t *args;
|
||||||
int32_t retVal;
|
int32_t retVal;
|
||||||
|
|
||||||
|
if (desc_ptr->iovec_api == TFM_SFN_API_IOVEC) {
|
||||||
|
res = tfm_core_check_sfn_parameters(desc_ptr);
|
||||||
|
if (res != TFM_SUCCESS) {
|
||||||
|
/* The sanity check of iovecs failed. */
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* No excReturn value is needed as no exception handling is used */
|
/* No excReturn value is needed as no exception handling is used */
|
||||||
res = tfm_core_sfn_request_handler(desc_ptr, 0);
|
res = tfm_core_sfn_request_handler(desc_ptr, 0);
|
||||||
|
|
||||||
|
@ -689,6 +1048,8 @@ void tfm_core_memory_permission_check_handler(uint32_t *svc_args)
|
||||||
uint32_t tfm_core_partition_request_svc_handler(
|
uint32_t tfm_core_partition_request_svc_handler(
|
||||||
struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
|
struct tfm_exc_stack_t *svc_ctx, uint32_t excReturn)
|
||||||
{
|
{
|
||||||
|
struct tfm_sfn_req_s *desc_ptr;
|
||||||
|
|
||||||
if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
|
if (!(excReturn & EXC_RETURN_STACK_PROCESS)) {
|
||||||
/* Service request SVC called with MSP active.
|
/* Service request SVC called with MSP active.
|
||||||
* Either invalid configuration for Thread mode or SVC called
|
* Either invalid configuration for Thread mode or SVC called
|
||||||
|
@ -699,7 +1060,7 @@ uint32_t tfm_core_partition_request_svc_handler(
|
||||||
tfm_secure_api_error_handler();
|
tfm_secure_api_error_handler();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tfm_sfn_req_s *desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
|
desc_ptr = (struct tfm_sfn_req_s *)svc_ctx->R0;
|
||||||
|
|
||||||
if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
|
if (tfm_core_sfn_request_handler(desc_ptr, excReturn) != TFM_SUCCESS) {
|
||||||
tfm_secure_api_error_handler();
|
tfm_secure_api_error_handler();
|
||||||
|
@ -724,17 +1085,19 @@ uint32_t tfm_core_partition_return_handler(uint32_t lr)
|
||||||
/* Store return value from secure partition */
|
/* Store return value from secure partition */
|
||||||
int32_t retVal = *(int32_t *)__get_PSP();
|
int32_t retVal = *(int32_t *)__get_PSP();
|
||||||
|
|
||||||
if ((retVal > TFM_SUCCESS) &&
|
if (!is_iovec_api_call()) {
|
||||||
(retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
|
if ((retVal > TFM_SUCCESS) &&
|
||||||
/* Secure function returned a reserved value */
|
(retVal < TFM_PARTITION_SPECIFIC_ERROR_MIN)) {
|
||||||
|
/* Secure function returned a reserved value */
|
||||||
#ifdef TFM_CORE_DEBUG
|
#ifdef TFM_CORE_DEBUG
|
||||||
LOG_MSG("Invalid return value from secure partition!");
|
LOG_MSG("Invalid return value from secure partition!");
|
||||||
#endif
|
#endif
|
||||||
/* FixMe: error can be traced to specific secure partition
|
/* FixMe: error can be traced to specific secure partition
|
||||||
* and Core is not compromised. Error handling flow can be
|
* and Core is not compromised. Error handling flow can be
|
||||||
* refined
|
* refined
|
||||||
*/
|
*/
|
||||||
tfm_secure_api_error_handler();
|
tfm_secure_api_error_handler();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = tfm_return_from_partition(&lr);
|
res = tfm_return_from_partition(&lr);
|
||||||
|
|
|
@ -29,6 +29,9 @@
|
||||||
#define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY)
|
#define TFM_ERROR_STATUS(status) (TFM_PARTITION_BUSY)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TFM_SFN_API_LEGACY 0
|
||||||
|
#define TFM_SFN_API_IOVEC 1
|
||||||
|
|
||||||
#ifndef TFM_LVL
|
#ifndef TFM_LVL
|
||||||
#error TFM_LVL is not defined!
|
#error TFM_LVL is not defined!
|
||||||
#endif
|
#endif
|
||||||
|
@ -42,6 +45,7 @@ struct tfm_sfn_req_s {
|
||||||
sfn_t sfn;
|
sfn_t sfn;
|
||||||
int32_t *args;
|
int32_t *args;
|
||||||
uint32_t caller_part_idx;
|
uint32_t caller_part_idx;
|
||||||
|
int32_t iovec_api;
|
||||||
int32_t ns_caller : 1;
|
int32_t ns_caller : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,8 +77,9 @@ extern int32_t tfm_core_validate_secure_caller(void);
|
||||||
|
|
||||||
extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
|
extern int32_t tfm_core_get_caller_client_id(int32_t *caller_client_id);
|
||||||
|
|
||||||
extern int32_t tfm_core_memory_permission_check(
|
extern int32_t tfm_core_memory_permission_check(const void *ptr,
|
||||||
void *ptr, uint32_t size, int32_t access);
|
uint32_t size,
|
||||||
|
int32_t access);
|
||||||
|
|
||||||
extern int32_t tfm_core_get_boot_data(uint8_t major_type, void *ptr,
|
extern int32_t tfm_core_get_boot_data(uint8_t major_type, void *ptr,
|
||||||
uint32_t len);
|
uint32_t len);
|
||||||
|
@ -83,12 +88,16 @@ int32_t tfm_core_sfn_request(struct tfm_sfn_req_s *desc_ptr);
|
||||||
|
|
||||||
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
|
int32_t tfm_core_sfn_request_thread_mode(struct tfm_sfn_req_s *desc_ptr);
|
||||||
|
|
||||||
|
#define TFM_CORE_IOVEC_SFN_REQUEST(id, fn, a, b, c, d) \
|
||||||
|
return tfm_core_partition_request(id, fn, TFM_SFN_API_IOVEC, \
|
||||||
|
(int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d)
|
||||||
|
|
||||||
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
|
#define TFM_CORE_SFN_REQUEST(id, fn, a, b, c, d) \
|
||||||
return tfm_core_partition_request(id, fn, (int32_t)a, (int32_t)b, \
|
return tfm_core_partition_request(id, fn, TFM_SFN_API_LEGACY, \
|
||||||
(int32_t)c, (int32_t)d)
|
(int32_t)a, (int32_t)b, (int32_t)c, (int32_t)d)
|
||||||
|
|
||||||
__attribute__ ((always_inline)) __STATIC_INLINE
|
__attribute__ ((always_inline)) __STATIC_INLINE
|
||||||
int32_t tfm_core_partition_request(uint32_t id, void *fn,
|
int32_t tfm_core_partition_request(uint32_t id, void *fn, int32_t iovec_api,
|
||||||
int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
|
int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4)
|
||||||
{
|
{
|
||||||
int32_t args[4] = {arg1, arg2, arg3, arg4};
|
int32_t args[4] = {arg1, arg2, arg3, arg4};
|
||||||
|
@ -98,6 +107,7 @@ int32_t tfm_core_partition_request(uint32_t id, void *fn,
|
||||||
desc.sfn = fn;
|
desc.sfn = fn;
|
||||||
desc.args = args;
|
desc.args = args;
|
||||||
desc.ns_caller = cmse_nonsecure_caller();
|
desc.ns_caller = cmse_nonsecure_caller();
|
||||||
|
desc.iovec_api = iovec_api;
|
||||||
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
|
if (__get_active_exc_num() != EXC_NUM_THREAD_MODE) {
|
||||||
/* FixMe: Error severity TBD */
|
/* FixMe: Error severity TBD */
|
||||||
return TFM_ERROR_GENERIC;
|
return TFM_ERROR_GENERIC;
|
||||||
|
|
|
@ -100,8 +100,9 @@ __attribute__((naked)) int32_t tfm_core_sfn_request(
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
__attribute__((naked))
|
__attribute__((naked))
|
||||||
int32_t tfm_core_memory_permission_check(
|
int32_t tfm_core_memory_permission_check(const void *ptr,
|
||||||
void *ptr, uint32_t len, int32_t access)
|
uint32_t len,
|
||||||
|
int32_t access)
|
||||||
{
|
{
|
||||||
__ASM(
|
__ASM(
|
||||||
"SVC %0\n"
|
"SVC %0\n"
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
//This file holds description for the current directory. This documentation
|
||||||
|
//will be included in the Doxygen output.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\dir
|
||||||
|
\brief Include files for the TF-M.
|
||||||
|
\details This directory currently only holds the include file for the SPM
|
||||||
|
module.
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,16 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
//This file holds description for the current directory. This documentation
|
||||||
|
//will be included in the Doxygen output.
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\dir
|
||||||
|
\brief Source code for the Secure Partition Manager.
|
||||||
|
\details This directory holds the source code of the "TF-M SPM" module.
|
||||||
|
|
||||||
|
*/
|
|
@ -11,13 +11,12 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "spm_api.h"
|
#include "spm_api.h"
|
||||||
#include "platform/include/tfm_spm_hal.h"
|
#include "platform/include/tfm_spm_hal.h"
|
||||||
#include "secure_utilities.h"
|
#include "tfm_memory_utils.h"
|
||||||
#include "spm_db_setup.h"
|
#include "spm_db_setup.h"
|
||||||
#include "tfm_internal.h"
|
#include "tfm_internal.h"
|
||||||
#include "tfm_api.h"
|
#include "tfm_api.h"
|
||||||
#include "tfm_nspm.h"
|
#include "tfm_nspm.h"
|
||||||
#include "secure_fw/core/tfm_core.h"
|
#include "secure_fw/core/tfm_core.h"
|
||||||
#include "platform_retarget.h"
|
|
||||||
#include "tfm_peripherals_def.h"
|
#include "tfm_peripherals_def.h"
|
||||||
#include "spm_partition_defs.h"
|
#include "spm_partition_defs.h"
|
||||||
|
|
||||||
|
@ -156,6 +155,7 @@ enum spm_err_t tfm_spm_partition_init(void)
|
||||||
|
|
||||||
desc.args = args;
|
desc.args = args;
|
||||||
desc.ns_caller = 0;
|
desc.ns_caller = 0;
|
||||||
|
desc.iovec_api = TFM_SFN_API_IOVEC;
|
||||||
desc.sfn = (sfn_t)part->static_data.partition_init;
|
desc.sfn = (sfn_t)part->static_data.partition_init;
|
||||||
desc.sp_id = part->static_data.partition_id;
|
desc.sp_id = part->static_data.partition_id;
|
||||||
res = tfm_core_sfn_request(&desc);
|
res = tfm_core_sfn_request(&desc);
|
||||||
|
@ -314,6 +314,29 @@ enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tfm_spm_partition_set_iovec(uint32_t partition_idx, int32_t *args)
|
||||||
|
{
|
||||||
|
struct spm_partition_runtime_data_t *runtime_data =
|
||||||
|
&g_spm_partition_db.partitions[partition_idx].runtime_data;
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
|
runtime_data->iovec_args.in_len = args[1];
|
||||||
|
for (i = 0; i < runtime_data->iovec_args.in_len; ++i) {
|
||||||
|
runtime_data->iovec_args.in_vec[i].base =
|
||||||
|
((psa_invec *)args[0])[i].base;
|
||||||
|
runtime_data->iovec_args.in_vec[i].len = ((psa_invec *)args[0])[i].len;
|
||||||
|
}
|
||||||
|
runtime_data->iovec_args.out_len = args[3];
|
||||||
|
for (i = 0; i < runtime_data->iovec_args.out_len; ++i) {
|
||||||
|
runtime_data->iovec_args.out_vec[i].base =
|
||||||
|
((psa_outvec *)args[2])[i].base;
|
||||||
|
runtime_data->iovec_args.out_vec[i].len =
|
||||||
|
((psa_outvec *)args[2])[i].len;
|
||||||
|
}
|
||||||
|
runtime_data->orig_outvec = (psa_outvec *)args[2];
|
||||||
|
runtime_data->iovec_api = 1;
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t tfm_spm_partition_get_running_partition_idx(void)
|
uint32_t tfm_spm_partition_get_running_partition_idx(void)
|
||||||
{
|
{
|
||||||
return g_spm_partition_db.running_partition_idx;
|
return g_spm_partition_db.running_partition_idx;
|
||||||
|
@ -323,6 +346,20 @@ void tfm_spm_partition_cleanup_context(uint32_t partition_idx)
|
||||||
{
|
{
|
||||||
struct spm_partition_desc_t *partition =
|
struct spm_partition_desc_t *partition =
|
||||||
&(g_spm_partition_db.partitions[partition_idx]);
|
&(g_spm_partition_db.partitions[partition_idx]);
|
||||||
|
int32_t i;
|
||||||
|
|
||||||
partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
|
partition->runtime_data.caller_partition_idx = SPM_INVALID_PARTITION_IDX;
|
||||||
partition->runtime_data.share = 0;
|
partition->runtime_data.share = 0;
|
||||||
|
partition->runtime_data.iovec_args.in_len = 0;
|
||||||
|
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
|
||||||
|
partition->runtime_data.iovec_args.in_vec[i].base = 0;
|
||||||
|
partition->runtime_data.iovec_args.in_vec[i].len = 0;
|
||||||
|
}
|
||||||
|
partition->runtime_data.iovec_args.out_len = 0;
|
||||||
|
for (i = 0; i < PSA_MAX_IOVEC; ++i) {
|
||||||
|
partition->runtime_data.iovec_args.out_vec[i].base = 0;
|
||||||
|
partition->runtime_data.iovec_args.out_vec[i].len = 0;
|
||||||
|
}
|
||||||
|
partition->runtime_data.orig_outvec = 0;
|
||||||
|
partition->runtime_data.iovec_api = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#define __SPM_API_H__
|
#define __SPM_API_H__
|
||||||
|
|
||||||
/* This file contains the apis exported by the SPM to tfm core */
|
/* This file contains the apis exported by the SPM to tfm core */
|
||||||
|
#include "tfm_api.h"
|
||||||
#include "spm_partition_defs.h"
|
#include "spm_partition_defs.h"
|
||||||
#include "secure_fw/core/tfm_secure_api.h"
|
#include "secure_fw/core/tfm_secure_api.h"
|
||||||
|
|
||||||
|
@ -37,6 +38,20 @@ enum spm_part_flag_mask_t {
|
||||||
SPM_PART_FLAG_IPC = 0x04
|
SPM_PART_FLAG_IPC = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Holds the iovec parameters that are passed to a service
|
||||||
|
*
|
||||||
|
* \note The size of the structure is (and have to be) multiple of 8 bytes
|
||||||
|
*/
|
||||||
|
struct iovec_args_t {
|
||||||
|
psa_invec in_vec[PSA_MAX_IOVEC]; /*!< Array of psa_invec objects */
|
||||||
|
size_t in_len; /*!< Number psa_invec objects in in_vec
|
||||||
|
*/
|
||||||
|
psa_outvec out_vec[PSA_MAX_IOVEC]; /*!< Array of psa_outvec objects */
|
||||||
|
size_t out_len; /*!< Number psa_outvec objects in out_vec
|
||||||
|
*/
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Runtime context information of a partition
|
* \brief Runtime context information of a partition
|
||||||
*/
|
*/
|
||||||
|
@ -47,6 +62,13 @@ struct spm_partition_runtime_data_t {
|
||||||
uint32_t share;
|
uint32_t share;
|
||||||
uint32_t stack_ptr;
|
uint32_t stack_ptr;
|
||||||
uint32_t lr;
|
uint32_t lr;
|
||||||
|
int32_t iovec_api; /*!< Whether the function in the partition
|
||||||
|
* had been called using the iovec API.
|
||||||
|
* FIXME: Remove the field once this is the
|
||||||
|
* only option
|
||||||
|
*/
|
||||||
|
struct iovec_args_t iovec_args;
|
||||||
|
psa_outvec *orig_outvec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -60,6 +82,7 @@ struct spm_partition_runtime_data_t {
|
||||||
*/
|
*/
|
||||||
uint32_t get_partition_idx(uint32_t partition_id);
|
uint32_t get_partition_idx(uint32_t partition_id);
|
||||||
|
|
||||||
|
#if TFM_LVL != 1
|
||||||
/**
|
/**
|
||||||
* \brief Configure isolated sandbox for a partition
|
* \brief Configure isolated sandbox for a partition
|
||||||
*
|
*
|
||||||
|
@ -104,28 +127,6 @@ uint32_t tfm_spm_partition_get_stack_bottom(uint32_t partition_idx);
|
||||||
*/
|
*/
|
||||||
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
|
uint32_t tfm_spm_partition_get_stack_top(uint32_t partition_idx);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the id of the partition for its index from the db
|
|
||||||
*
|
|
||||||
* \param[in] partition_idx Partition index
|
|
||||||
*
|
|
||||||
* \return Partition ID for that partition
|
|
||||||
*
|
|
||||||
* \note This function doesn't check if partition_idx is valid.
|
|
||||||
*/
|
|
||||||
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Get the flags associated with a partition
|
|
||||||
*
|
|
||||||
* \param[in] partition_idx Partition index
|
|
||||||
*
|
|
||||||
* \return Flags associated with the partition
|
|
||||||
*
|
|
||||||
* \note This function doesn't check if partition_idx is valid.
|
|
||||||
*/
|
|
||||||
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get the start of the zero-initialised region for a partition
|
* \brief Get the start of the zero-initialised region for a partition
|
||||||
*
|
*
|
||||||
|
@ -172,6 +173,28 @@ uint32_t tfm_spm_partition_get_rw_start(uint32_t partition_idx);
|
||||||
*/
|
*/
|
||||||
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
|
uint32_t tfm_spm_partition_get_rw_limit(uint32_t partition_idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Save stack pointer for partition in database
|
||||||
|
*
|
||||||
|
* \param[in] partition_idx Partition index
|
||||||
|
* \param[in] stack_ptr Stack pointer to be stored
|
||||||
|
*
|
||||||
|
* \note This function doesn't check if partition_idx is valid.
|
||||||
|
*/
|
||||||
|
void tfm_spm_partition_set_stack(uint32_t partition_idx, uint32_t stack_ptr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the flags associated with a partition
|
||||||
|
*
|
||||||
|
* \param[in] partition_idx Partition index
|
||||||
|
*
|
||||||
|
* \return Flags associated with the partition
|
||||||
|
*
|
||||||
|
* \note This function doesn't check if partition_idx is valid.
|
||||||
|
*/
|
||||||
|
uint32_t tfm_spm_partition_get_flags(uint32_t partition_idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get the current runtime data of a partition
|
* \brief Get the current runtime data of a partition
|
||||||
*
|
*
|
||||||
|
@ -192,16 +215,6 @@ const struct spm_partition_runtime_data_t *
|
||||||
*/
|
*/
|
||||||
uint32_t tfm_spm_partition_get_running_partition_idx(void);
|
uint32_t tfm_spm_partition_get_running_partition_idx(void);
|
||||||
|
|
||||||
/**
|
|
||||||
* \brief Save stack pointer for partition in database
|
|
||||||
*
|
|
||||||
* \param[in] partition_idx Partition index
|
|
||||||
* \param[in] stack_ptr Stack pointer to be stored
|
|
||||||
*
|
|
||||||
* \note This function doesn't check if partition_idx is valid.
|
|
||||||
*/
|
|
||||||
void tfm_spm_partition_set_stack(uint32_t partition_id, uint32_t stack_ptr);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Save stack pointer and link register for partition in database
|
* \brief Save stack pointer and link register for partition in database
|
||||||
*
|
*
|
||||||
|
@ -214,6 +227,17 @@ void tfm_spm_partition_set_stack(uint32_t partition_id, uint32_t stack_ptr);
|
||||||
void tfm_spm_partition_store_context(uint32_t partition_idx,
|
void tfm_spm_partition_store_context(uint32_t partition_idx,
|
||||||
uint32_t stack_ptr, uint32_t lr);
|
uint32_t stack_ptr, uint32_t lr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Get the id of the partition for its index from the db
|
||||||
|
*
|
||||||
|
* \param[in] partition_idx Partition index
|
||||||
|
*
|
||||||
|
* \return Partition ID for that partition
|
||||||
|
*
|
||||||
|
* \note This function doesn't check if partition_idx is valid.
|
||||||
|
*/
|
||||||
|
uint32_t tfm_spm_partition_get_partition_id(uint32_t partition_idx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Set the current state of a partition
|
* \brief Set the current state of a partition
|
||||||
*
|
*
|
||||||
|
@ -221,7 +245,7 @@ void tfm_spm_partition_store_context(uint32_t partition_idx,
|
||||||
* \param[in] state The state to be set
|
* \param[in] state The state to be set
|
||||||
*
|
*
|
||||||
* \note This function doesn't check if partition_idx is valid.
|
* \note This function doesn't check if partition_idx is valid.
|
||||||
* \note The \ref state has to have the value set of \ref spm_part_state_t.
|
* \note The state has to have the value set of \ref spm_part_state_t.
|
||||||
*/
|
*/
|
||||||
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
|
void tfm_spm_partition_set_state(uint32_t partition_idx, uint32_t state);
|
||||||
|
|
||||||
|
@ -261,6 +285,24 @@ void tfm_spm_partition_set_caller_client_id(uint32_t partition_idx,
|
||||||
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
|
enum spm_err_t tfm_spm_partition_set_share(uint32_t partition_idx,
|
||||||
uint32_t share);
|
uint32_t share);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief Set the iovec parameters for the partition
|
||||||
|
*
|
||||||
|
* \param[in] partition_idx Partition index
|
||||||
|
* \param[in] args The arguments of the secure function
|
||||||
|
*
|
||||||
|
* args is expected to be of type int32_t[4] where:
|
||||||
|
* args[0] is in_vec
|
||||||
|
* args[1] is in_len
|
||||||
|
* args[2] is out_vec
|
||||||
|
* args[3] is out_len
|
||||||
|
*
|
||||||
|
* \note This function doesn't check if partition_idx is valid.
|
||||||
|
* \note This function assumes that the iovecs that are passed in args are
|
||||||
|
* valid, and does no sanity check on them at all.
|
||||||
|
*/
|
||||||
|
void tfm_spm_partition_set_iovec(uint32_t partition_idx, int32_t *args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Initialize partition database
|
* \brief Initialize partition database
|
||||||
*
|
*
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#ifndef __SPM_DB_H__
|
#ifndef __SPM_DB_H__
|
||||||
#define __SPM_DB_H__
|
#define __SPM_DB_H__
|
||||||
|
|
||||||
|
|
||||||
#ifdef TFM_PSA_API
|
#ifdef TFM_PSA_API
|
||||||
#include "tfm_thread.h"
|
#include "tfm_thread.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -15,9 +16,7 @@
|
||||||
struct spm_partition_desc_t;
|
struct spm_partition_desc_t;
|
||||||
struct spm_partition_db_t;
|
struct spm_partition_db_t;
|
||||||
|
|
||||||
uint32_t get_partition_idx(uint32_t partition_id);
|
typedef psa_status_t(*sp_init_function)(void);
|
||||||
|
|
||||||
typedef int32_t(*sp_init_function)(void);
|
|
||||||
|
|
||||||
#define TFM_PARTITION_TYPE_APP "APPLICATION-ROT"
|
#define TFM_PARTITION_TYPE_APP "APPLICATION-ROT"
|
||||||
#define TFM_PARTITION_TYPE_PSA "PSA-ROT"
|
#define TFM_PARTITION_TYPE_PSA "PSA-ROT"
|
||||||
|
|
|
@ -17,10 +17,10 @@
|
||||||
* Gets the index of a partition in the partition db based on the partition ID
|
* Gets the index of a partition in the partition db based on the partition ID
|
||||||
* provided as a parameter.
|
* provided as a parameter.
|
||||||
*
|
*
|
||||||
* \param[in] partition_id The ID of the partition
|
* \param[in] partition_idx The index of the partition
|
||||||
*
|
*
|
||||||
* \return \ref INVALID_PARTITION_IDX if the provided ID is invalid. The index
|
* \return \ref INVALID_PARTITION_IDX if the provided index is invalid. The
|
||||||
* of the partition otherwise.
|
* index of the partition otherwise.
|
||||||
*/
|
*/
|
||||||
uint32_t get_partition_idx(uint32_t partition_id);
|
uint32_t get_partition_idx(uint32_t partition_id);
|
||||||
|
|
||||||
|
@ -66,8 +66,13 @@ struct spm_partition_db_t {
|
||||||
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
|
#define PARTITION_INIT_RUNTIME_DATA(data, partition) \
|
||||||
do { \
|
do { \
|
||||||
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
|
data.partition_state = SPM_PARTITION_STATE_UNINIT; \
|
||||||
|
/* The top of the stack is reserved for the iovec */ \
|
||||||
|
/* parameters of the service called. That's why in */ \
|
||||||
|
/* data.stack_ptr we extract sizeof(struct iovec_args_t) */ \
|
||||||
|
/* from the limit. */ \
|
||||||
data.stack_ptr = \
|
data.stack_ptr = \
|
||||||
PART_REGION_ADDR(partition, _STACK$$ZI$$Limit); \
|
PART_REGION_ADDR(partition, _STACK$$ZI$$Limit - \
|
||||||
|
sizeof(struct iovec_args_t)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2018, Arm Limited. All rights reserved.
|
* Copyright (c) 2018-2019, Arm Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
*
|
*
|
||||||
|
|
|
@ -223,8 +223,6 @@ void psa_notify(int32_t partition_id);
|
||||||
/**
|
/**
|
||||||
* \brief Clear the PSA_DOORBELL signal.
|
* \brief Clear the PSA_DOORBELL signal.
|
||||||
*
|
*
|
||||||
* \param[in] void
|
|
||||||
*
|
|
||||||
* \retval void Success.
|
* \retval void Success.
|
||||||
* \retval "Does not return" The Secure Partition's doorbell signal is not
|
* \retval "Does not return" The Secure Partition's doorbell signal is not
|
||||||
* currently asserted.
|
* currently asserted.
|
||||||
|
|
|
@ -13,7 +13,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "interface/include/psa_client.h"
|
#include "psa_client.h"
|
||||||
|
|
||||||
#define TFM_INVALID_CLIENT_ID 0
|
#define TFM_INVALID_CLIENT_ID 0
|
||||||
|
|
||||||
|
@ -35,13 +35,18 @@ extern "C" {
|
||||||
*/
|
*/
|
||||||
#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0)
|
#define TFM_CLIENT_ID_IS_NS(client_id) ((client_id)<0)
|
||||||
|
|
||||||
|
/* Maximum number of input and output vectors */
|
||||||
|
#define PSA_MAX_IOVEC (4)
|
||||||
|
|
||||||
/* FixMe: sort out DEBUG compile option and limit return value options
|
/* FixMe: sort out DEBUG compile option and limit return value options
|
||||||
* on external interfaces */
|
* on external interfaces */
|
||||||
/* Note:
|
/* For secure functions using prorietary signatures
|
||||||
* TFM will only return values recognized and parsed by TFM core.
|
* TFM will only return values recognized and parsed by TFM core.
|
||||||
* Service return codes are not automatically passed on to REE.
|
* Service return codes are not automatically passed on to REE.
|
||||||
* Any non-zero return value is interpreted as an error that may trigger
|
* Any non-zero return value is interpreted as an error that may trigger
|
||||||
* TEE error handling flow.
|
* TEE error handling flow.
|
||||||
|
* For secure functions using the veneers in secure_fw/ns_callable/tfm_veneers.c
|
||||||
|
* (iovec API) this limitation does not apply.
|
||||||
*/
|
*/
|
||||||
enum tfm_status_e
|
enum tfm_status_e
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#if defined(TARGET_TFM)
|
#if defined(TARGET_TFM)
|
||||||
|
|
||||||
#include "interface/include/psa_service.h"
|
#include "interface/include/psa_service.h"
|
||||||
|
#include "secure_fw/core/ipc/include/tfm_utils.h"
|
||||||
#define SPM_PANIC(format, ...) tfm_panic()
|
#define SPM_PANIC(format, ...) tfm_panic()
|
||||||
|
|
||||||
#elif defined(TARGET_MBED_SPM)
|
#elif defined(TARGET_MBED_SPM)
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "tfm_plat_boot_seed.h"
|
#include "tfm_plat_boot_seed.h"
|
||||||
|
@ -154,7 +155,7 @@ enum psa_attest_err_t attest_get_caller_client_id(int32_t *caller_id)
|
||||||
/* Boot seed data is part of bootloader status*/
|
/* Boot seed data is part of bootloader status*/
|
||||||
enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf)
|
enum tfm_plat_err_t tfm_plat_get_boot_seed(uint32_t size, uint8_t *buf)
|
||||||
{
|
{
|
||||||
return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
|
return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -181,13 +182,13 @@ enum tfm_plat_err_t tfm_plat_get_instance_id(uint32_t *size, uint8_t *buf)
|
||||||
/* HW version data is part of bootloader status*/
|
/* HW version data is part of bootloader status*/
|
||||||
enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf)
|
enum tfm_plat_err_t tfm_plat_get_hw_version(uint32_t *size, uint8_t *buf)
|
||||||
{
|
{
|
||||||
return PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
|
return (enum tfm_plat_err_t)PSA_ATTEST_ERR_CLAIM_UNAVAILABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, uint8_t *buf)
|
enum tfm_plat_err_t tfm_plat_get_implementation_id(uint32_t *size, uint8_t *buf)
|
||||||
{
|
{
|
||||||
memcpy(buf, impl_id_data, *size);
|
memcpy(buf, impl_id_data, *size);
|
||||||
return PSA_ATTEST_ERR_SUCCESS;
|
return (enum tfm_plat_err_t)PSA_ATTEST_ERR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Temporary Implementation of security lifecycle data: mandatory claim.
|
/* Temporary Implementation of security lifecycle data: mandatory claim.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "psa_attest_inject_key.h"
|
#include "psa_attest_inject_key.h"
|
||||||
#include "psa_inject_attestation_key_impl.h"
|
#include "psa_inject_attestation_key_impl.h"
|
||||||
#include "attestation.h"
|
#include "attestation.h"
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "psa/crypto.h"
|
#include "psa/crypto.h"
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,10 @@ static psa_status_t psa_mac_setup(psa_mac_operation_t *operation,
|
||||||
psa_algorithm_t alg,
|
psa_algorithm_t alg,
|
||||||
psa_sec_function_t func)
|
psa_sec_function_t func)
|
||||||
{
|
{
|
||||||
|
if (operation->handle != PSA_NULL_HANDLE) {
|
||||||
|
return (PSA_ERROR_BAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
psa_crypto_ipc_t psa_crypto_ipc = {
|
psa_crypto_ipc_t psa_crypto_ipc = {
|
||||||
.func = func,
|
.func = func,
|
||||||
.handle = key_handle,
|
.handle = key_handle,
|
||||||
|
@ -133,6 +137,9 @@ static psa_status_t psa_mac_setup(psa_mac_operation_t *operation,
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,6 +175,9 @@ psa_status_t psa_mac_update(psa_mac_operation_t *operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -240,6 +250,10 @@ psa_status_t psa_hash_abort(psa_hash_operation_t *operation)
|
||||||
psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
|
psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
|
||||||
psa_algorithm_t alg)
|
psa_algorithm_t alg)
|
||||||
{
|
{
|
||||||
|
if (operation->handle != PSA_NULL_HANDLE) {
|
||||||
|
return (PSA_ERROR_BAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
psa_crypto_ipc_t psa_crypto_ipc = {
|
psa_crypto_ipc_t psa_crypto_ipc = {
|
||||||
.func = PSA_HASH_SETUP,
|
.func = PSA_HASH_SETUP,
|
||||||
.handle = 0,
|
.handle = 0,
|
||||||
|
@ -253,6 +267,9 @@ psa_status_t psa_hash_setup(psa_hash_operation_t *operation,
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,6 +289,9 @@ psa_status_t psa_hash_update(psa_hash_operation_t *operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -986,6 +1006,10 @@ psa_status_t psa_key_derivation(psa_crypto_generator_t *generator,
|
||||||
size_t label_length,
|
size_t label_length,
|
||||||
size_t capacity)
|
size_t capacity)
|
||||||
{
|
{
|
||||||
|
if (generator->handle != PSA_NULL_HANDLE) {
|
||||||
|
return (PSA_ERROR_BAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
psa_crypto_derivation_ipc_t psa_crypto_ipc = {
|
psa_crypto_derivation_ipc_t psa_crypto_ipc = {
|
||||||
.func = PSA_KEY_DERIVATION,
|
.func = PSA_KEY_DERIVATION,
|
||||||
.handle = key_handle,
|
.handle = key_handle,
|
||||||
|
@ -1004,6 +1028,9 @@ psa_status_t psa_key_derivation(psa_crypto_generator_t *generator,
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
status = ipc_call(&generator->handle, in_vec, 3, NULL, 0, false);
|
status = ipc_call(&generator->handle, in_vec, 3, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&generator->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1013,6 +1040,10 @@ psa_status_t psa_key_agreement(psa_crypto_generator_t *generator,
|
||||||
size_t peer_key_length,
|
size_t peer_key_length,
|
||||||
psa_algorithm_t alg)
|
psa_algorithm_t alg)
|
||||||
{
|
{
|
||||||
|
if (generator->handle != PSA_NULL_HANDLE) {
|
||||||
|
return (PSA_ERROR_BAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
psa_crypto_derivation_ipc_t psa_crypto_ipc = {
|
psa_crypto_derivation_ipc_t psa_crypto_ipc = {
|
||||||
.func = PSA_KEY_AGREEMENT,
|
.func = PSA_KEY_AGREEMENT,
|
||||||
.handle = private_key_handle,
|
.handle = private_key_handle,
|
||||||
|
@ -1030,6 +1061,9 @@ psa_status_t psa_key_agreement(psa_crypto_generator_t *generator,
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
status = ipc_call(&generator->handle, in_vec, 2, NULL, 0, false);
|
status = ipc_call(&generator->handle, in_vec, 2, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&generator->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,12 +1089,17 @@ psa_status_t psa_generator_abort(psa_crypto_generator_t *generator)
|
||||||
/****************************************************************/
|
/****************************************************************/
|
||||||
/* SYMMETRIC */
|
/* SYMMETRIC */
|
||||||
/****************************************************************/
|
/****************************************************************/
|
||||||
psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
|
static psa_status_t psa_cipher_setup(psa_cipher_operation_t *operation,
|
||||||
psa_key_handle_t key_handle,
|
psa_key_handle_t key_handle,
|
||||||
psa_algorithm_t alg)
|
psa_algorithm_t alg,
|
||||||
|
psa_sec_function_t func)
|
||||||
{
|
{
|
||||||
|
if (operation->handle != PSA_NULL_HANDLE) {
|
||||||
|
return (PSA_ERROR_BAD_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
psa_crypto_ipc_t psa_crypto_ipc = {
|
psa_crypto_ipc_t psa_crypto_ipc = {
|
||||||
.func = PSA_CIPHER_ENCRYPT_SETUP,
|
.func = func,
|
||||||
.handle = key_handle,
|
.handle = key_handle,
|
||||||
.alg = alg
|
.alg = alg
|
||||||
};
|
};
|
||||||
|
@ -1072,6 +1111,17 @@ psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
|
return (status);
|
||||||
|
}
|
||||||
|
|
||||||
|
psa_status_t psa_cipher_encrypt_setup(psa_cipher_operation_t *operation,
|
||||||
|
psa_key_handle_t key_handle,
|
||||||
|
psa_algorithm_t alg)
|
||||||
|
{
|
||||||
|
psa_status_t status = psa_cipher_setup(operation, key_handle, alg, PSA_CIPHER_ENCRYPT_SETUP);
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1079,19 +1129,7 @@ psa_status_t psa_cipher_decrypt_setup(psa_cipher_operation_t *operation,
|
||||||
psa_key_handle_t key_handle,
|
psa_key_handle_t key_handle,
|
||||||
psa_algorithm_t alg)
|
psa_algorithm_t alg)
|
||||||
{
|
{
|
||||||
psa_crypto_ipc_t psa_crypto_ipc = {
|
psa_status_t status = psa_cipher_setup(operation, key_handle, alg, PSA_CIPHER_DECRYPT_SETUP);
|
||||||
.func = PSA_CIPHER_DECRYPT_SETUP,
|
|
||||||
.handle = key_handle,
|
|
||||||
.alg = alg
|
|
||||||
};
|
|
||||||
|
|
||||||
psa_invec in_vec = { &psa_crypto_ipc, sizeof(psa_crypto_ipc) };
|
|
||||||
|
|
||||||
psa_status_t status = ipc_connect(PSA_SYMMETRIC_ID, &operation->handle);
|
|
||||||
if (status != PSA_SUCCESS) {
|
|
||||||
return (status);
|
|
||||||
}
|
|
||||||
status = ipc_call(&operation->handle, &in_vec, 1, NULL, 0, false);
|
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1114,6 +1152,9 @@ psa_status_t psa_cipher_generate_iv(psa_cipher_operation_t *operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, false);
|
psa_status_t status = ipc_call(&operation->handle, &in_vec, 1, out_vec, 2, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1133,6 +1174,9 @@ psa_status_t psa_cipher_set_iv(psa_cipher_operation_t *operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, NULL, 0, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1160,6 +1204,9 @@ psa_status_t psa_cipher_update(psa_cipher_operation_t *operation,
|
||||||
};
|
};
|
||||||
|
|
||||||
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false);
|
psa_status_t status = ipc_call(&operation->handle, in_vec, 2, out_vec, 2, false);
|
||||||
|
if (status != PSA_SUCCESS) {
|
||||||
|
ipc_close(&operation->handle);
|
||||||
|
}
|
||||||
return (status);
|
return (status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -15,6 +15,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "psa/client.h"
|
#include "psa/client.h"
|
||||||
#include "psa/service.h"
|
#include "psa/service.h"
|
||||||
|
@ -25,6 +26,8 @@
|
||||||
|
|
||||||
#if defined(TARGET_MBED_SPM)
|
#if defined(TARGET_MBED_SPM)
|
||||||
#include "kv_config.h"
|
#include "kv_config.h"
|
||||||
|
#else
|
||||||
|
int kv_init_storage_config();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
|
@ -15,8 +15,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT)
|
#if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT)
|
||||||
|
#ifndef __STDC_FORMAT_MACROS
|
||||||
|
#define __STDC_FORMAT_MACROS
|
||||||
|
#endif
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "ESP8266.h"
|
#include "ESP8266.h"
|
||||||
|
@ -601,7 +605,7 @@ nsapi_error_t ESP8266::send(int id, const void *data, uint32_t amount)
|
||||||
set_timeout(ESP8266_SEND_TIMEOUT);
|
set_timeout(ESP8266_SEND_TIMEOUT);
|
||||||
_busy = false;
|
_busy = false;
|
||||||
_error = false;
|
_error = false;
|
||||||
if (!_parser.send("AT+CIPSEND=%d,%lu", id, amount)) {
|
if (!_parser.send("AT+CIPSEND=%d,%" PRIu32, id, amount)) {
|
||||||
tr_debug("ESP8266::send(): AT+CIPSEND failed");
|
tr_debug("ESP8266::send(): AT+CIPSEND failed");
|
||||||
goto END;
|
goto END;
|
||||||
}
|
}
|
||||||
|
@ -734,7 +738,7 @@ int32_t ESP8266::_recv_tcp_passive(int id, void *data, uint32_t amount, uint32_t
|
||||||
amount = amount > 2048 ? 2048 : amount;
|
amount = amount > 2048 ? 2048 : amount;
|
||||||
|
|
||||||
// NOTE: documentation v3.0 says '+CIPRECVDATA:<data_len>,' but it's not how the FW responds...
|
// NOTE: documentation v3.0 says '+CIPRECVDATA:<data_len>,' but it's not how the FW responds...
|
||||||
bool done = _parser.send("AT+CIPRECVDATA=%d,%lu", id, amount)
|
bool done = _parser.send("AT+CIPRECVDATA=%d,%" PRIu32, id, amount)
|
||||||
&& _parser.recv("OK\n");
|
&& _parser.recv("OK\n");
|
||||||
|
|
||||||
_sock_i[id].tcp_data = NULL;
|
_sock_i[id].tcp_data = NULL;
|
||||||
|
@ -1052,7 +1056,7 @@ void ESP8266::_oob_tcp_data_hdlr()
|
||||||
|
|
||||||
MBED_ASSERT(_sock_active_id >= 0 && _sock_active_id < 5);
|
MBED_ASSERT(_sock_active_id >= 0 && _sock_active_id < 5);
|
||||||
|
|
||||||
if (!_parser.recv("%ld:", &len)) {
|
if (!_parser.recv("%" SCNd32 ":", &len)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,13 +174,20 @@ void ESP8266Interface::_connect_async()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_connect_retval = _esp.connect(ap_ssid, ap_pass);
|
_connect_retval = _esp.connect(ap_ssid, ap_pass);
|
||||||
|
int timeleft_ms = ESP8266_INTERFACE_CONNECT_TIMEOUT_MS - _conn_timer.read_ms();
|
||||||
if (_connect_retval == NSAPI_ERROR_OK || _connect_retval == NSAPI_ERROR_AUTH_FAILURE
|
if (_connect_retval == NSAPI_ERROR_OK || _connect_retval == NSAPI_ERROR_AUTH_FAILURE
|
||||||
|| _connect_retval == NSAPI_ERROR_NO_SSID) {
|
|| _connect_retval == NSAPI_ERROR_NO_SSID
|
||||||
|
|| ((_if_blocking == true) && (timeleft_ms <= 0))) {
|
||||||
_connect_event_id = 0;
|
_connect_event_id = 0;
|
||||||
|
_conn_timer.stop();
|
||||||
|
if (timeleft_ms <= 0) {
|
||||||
|
_connect_retval = NSAPI_ERROR_CONNECTION_TIMEOUT;
|
||||||
|
}
|
||||||
_if_connected.notify_all();
|
_if_connected.notify_all();
|
||||||
} else {
|
} else {
|
||||||
// Postpone to give other stuff time to run
|
// Postpone to give other stuff time to run
|
||||||
_connect_event_id = _global_event_queue->call_in(ESP8266_CONNECT_TIMEOUT, callback(this, &ESP8266Interface::_connect_async));
|
_connect_event_id = _global_event_queue->call_in(ESP8266_INTERFACE_CONNECT_INTERVAL_MS,
|
||||||
|
callback(this, &ESP8266Interface::_connect_async));
|
||||||
if (!_connect_event_id) {
|
if (!_connect_event_id) {
|
||||||
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
|
MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER, MBED_ERROR_CODE_ENOMEM), \
|
||||||
"ESP8266Interface::_connect_async(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
|
"ESP8266Interface::_connect_async(): unable to add event to queue. Increase \"events.shared-eventsize\"\n");
|
||||||
|
@ -223,6 +230,9 @@ int ESP8266Interface::connect()
|
||||||
|
|
||||||
_connect_retval = NSAPI_ERROR_NO_CONNECTION;
|
_connect_retval = NSAPI_ERROR_NO_CONNECTION;
|
||||||
MBED_ASSERT(!_connect_event_id);
|
MBED_ASSERT(!_connect_event_id);
|
||||||
|
_conn_timer.stop();
|
||||||
|
_conn_timer.reset();
|
||||||
|
_conn_timer.start();
|
||||||
_connect_event_id = _global_event_queue->call(callback(this, &ESP8266Interface::_connect_async));
|
_connect_event_id = _global_event_queue->call(callback(this, &ESP8266Interface::_connect_async));
|
||||||
|
|
||||||
if (!_connect_event_id) {
|
if (!_connect_event_id) {
|
||||||
|
@ -305,7 +315,7 @@ int ESP8266Interface::disconnect()
|
||||||
_initialized = false;
|
_initialized = false;
|
||||||
|
|
||||||
nsapi_error_t status = _conn_status_to_error();
|
nsapi_error_t status = _conn_status_to_error();
|
||||||
if (status == NSAPI_ERROR_NO_CONNECTION || !get_ip_address()) {
|
if (status == NSAPI_ERROR_NO_CONNECTION) {
|
||||||
return NSAPI_ERROR_NO_CONNECTION;
|
return NSAPI_ERROR_NO_CONNECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT)
|
#if DEVICE_SERIAL && DEVICE_INTERRUPTIN && defined(MBED_CONF_EVENTS_PRESENT) && defined(MBED_CONF_NSAPI_PRESENT) && defined(MBED_CONF_RTOS_PRESENT)
|
||||||
#include "drivers/DigitalOut.h"
|
#include "drivers/DigitalOut.h"
|
||||||
|
#include "drivers/Timer.h"
|
||||||
#include "ESP8266/ESP8266.h"
|
#include "ESP8266/ESP8266.h"
|
||||||
#include "events/EventQueue.h"
|
#include "events/EventQueue.h"
|
||||||
#include "events/mbed_shared_queues.h"
|
#include "events/mbed_shared_queues.h"
|
||||||
|
@ -34,6 +35,9 @@
|
||||||
|
|
||||||
#define ESP8266_SOCKET_COUNT 5
|
#define ESP8266_SOCKET_COUNT 5
|
||||||
|
|
||||||
|
#define ESP8266_INTERFACE_CONNECT_INTERVAL_MS (5000)
|
||||||
|
#define ESP8266_INTERFACE_CONNECT_TIMEOUT_MS (2 * ESP8266_CONNECT_TIMEOUT + ESP8266_INTERFACE_CONNECT_INTERVAL_MS)
|
||||||
|
|
||||||
#ifdef TARGET_FF_ARDUINO
|
#ifdef TARGET_FF_ARDUINO
|
||||||
#ifndef MBED_CONF_ESP8266_TX
|
#ifndef MBED_CONF_ESP8266_TX
|
||||||
#define MBED_CONF_ESP8266_TX D1
|
#define MBED_CONF_ESP8266_TX D1
|
||||||
|
@ -82,6 +86,9 @@ public:
|
||||||
*
|
*
|
||||||
* Attempts to connect to a WiFi network.
|
* Attempts to connect to a WiFi network.
|
||||||
*
|
*
|
||||||
|
* If interface is configured blocking it will timeout after up to
|
||||||
|
* ESP8266_INTERFACE_CONNECT_TIMEOUT_MS + ESP8266_CONNECT_TIMEOUT ms.
|
||||||
|
*
|
||||||
* @param ssid Name of the network to connect to
|
* @param ssid Name of the network to connect to
|
||||||
* @param pass Security passphrase to connect to the network
|
* @param pass Security passphrase to connect to the network
|
||||||
* @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
|
* @param security Type of encryption for connection (Default: NSAPI_SECURITY_NONE)
|
||||||
|
@ -355,6 +362,7 @@ private:
|
||||||
|
|
||||||
// connect status reporting
|
// connect status reporting
|
||||||
nsapi_error_t _conn_status_to_error();
|
nsapi_error_t _conn_status_to_error();
|
||||||
|
mbed::Timer _conn_timer;
|
||||||
|
|
||||||
// Drivers's socket info
|
// Drivers's socket info
|
||||||
struct _sock_info {
|
struct _sock_info {
|
||||||
|
|
|
@ -55,7 +55,7 @@ TDBStore includes the following design basics:
|
||||||
|
|
||||||
All writes occur sequentially on the physical storage as records, superseding the previous ones for the same key. Each data record is written right after the last written one. If a key is updated, a new record with this key is written, overriding the previous value of this key. If a key is deleted, a new record with a "deleted" flag is added.
|
All writes occur sequentially on the physical storage as records, superseding the previous ones for the same key. Each data record is written right after the last written one. If a key is updated, a new record with this key is written, overriding the previous value of this key. If a key is deleted, a new record with a "deleted" flag is added.
|
||||||
|
|
||||||
Writes expect the storage to be erased. However, TDBStore takes the "erase as you go" approcah, meaning that when it crosses a sector boundary, it checks whether the next sector is erased. If not, it erases the next sector. This saves time during initialization and garbage collection.
|
Writes expect the storage to be erased. However, TDBStore takes the "erase as you go" approach, meaning that when it crosses a sector boundary, it checks whether the next sector is erased. If not, it erases the next sector. This saves time during initialization and garbage collection.
|
||||||
|
|
||||||
### Memory layout and areas
|
### Memory layout and areas
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,10 @@
|
||||||
namespace mbed {
|
namespace mbed {
|
||||||
/** \addtogroup drivers */
|
/** \addtogroup drivers */
|
||||||
|
|
||||||
/** A digital input output bus, used for setting the state of a collection of pins
|
/** A digital input output bus, used for setting the state of a collection of pins.
|
||||||
|
* Implemented as an array of DigitalInOut pins, the bus can be constructed by any
|
||||||
|
* pins without restriction other than being capable of digital input or output
|
||||||
|
* capabilities
|
||||||
*
|
*
|
||||||
* @note Synchronization level: Thread safe
|
* @note Synchronization level: Thread safe
|
||||||
* @ingroup drivers
|
* @ingroup drivers
|
||||||
|
@ -33,7 +36,7 @@ class BusInOut : private NonCopyable<BusInOut> {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Create an BusInOut, connected to the specified pins
|
/** Create a BusInOut, connected to the specified pins
|
||||||
*
|
*
|
||||||
* @param p0 DigitalInOut pin to connect to bus bit
|
* @param p0 DigitalInOut pin to connect to bus bit
|
||||||
* @param p1 DigitalInOut pin to connect to bus bit
|
* @param p1 DigitalInOut pin to connect to bus bit
|
||||||
|
@ -61,9 +64,11 @@ public:
|
||||||
PinName p8 = NC, PinName p9 = NC, PinName p10 = NC, PinName p11 = NC,
|
PinName p8 = NC, PinName p9 = NC, PinName p10 = NC, PinName p11 = NC,
|
||||||
PinName p12 = NC, PinName p13 = NC, PinName p14 = NC, PinName p15 = NC);
|
PinName p12 = NC, PinName p13 = NC, PinName p14 = NC, PinName p15 = NC);
|
||||||
|
|
||||||
/** Create an BusInOut, connected to the specified pins
|
/** Create a BusInOut, connected to the specified pins
|
||||||
*
|
*
|
||||||
* @param pins An array of pins to construct a BusInOut from
|
* @param pins An array of pins (PinName) to construct a BusInOut from. The maximum
|
||||||
|
* number of pins in the array is 16 and any pins that are unspecified or are not to be
|
||||||
|
* connected must be specified as NC in the array that is passed in
|
||||||
*/
|
*/
|
||||||
BusInOut(PinName pins[16]);
|
BusInOut(PinName pins[16]);
|
||||||
|
|
||||||
|
@ -111,7 +116,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
/** A shorthand for write()
|
/** A shorthand for write()
|
||||||
* \sa BusInOut::write()
|
* \sa BusInOut::write()
|
||||||
*/
|
*/
|
||||||
BusInOut &operator= (int v);
|
BusInOut &operator= (int v);
|
||||||
BusInOut &operator= (BusInOut &rhs);
|
BusInOut &operator= (BusInOut &rhs);
|
||||||
|
@ -125,8 +130,9 @@ public:
|
||||||
* \sa BusInOut::read()
|
* \sa BusInOut::read()
|
||||||
*/
|
*/
|
||||||
operator int();
|
operator int();
|
||||||
#if !defined(DOXYGEN_ONLY)
|
|
||||||
protected:
|
protected:
|
||||||
|
#if !defined(DOXYGEN_ONLY)
|
||||||
virtual void lock();
|
virtual void lock();
|
||||||
virtual void unlock();
|
virtual void unlock();
|
||||||
DigitalInOut *_pin[16];
|
DigitalInOut *_pin[16];
|
||||||
|
@ -138,7 +144,7 @@ protected:
|
||||||
int _nc_mask;
|
int _nc_mask;
|
||||||
|
|
||||||
PlatformMutex _mutex;
|
PlatformMutex _mutex;
|
||||||
#endif
|
#endif //!defined(DOXYGEN_ONLY)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mbed
|
} // namespace mbed
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2019 Arm Limited and affiliates.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
|
@ -0,0 +1,7 @@
|
||||||
|
Unless specifically indicated otherwise in a file or in the list below, files are licensed under the Apache 2.0 license,
|
||||||
|
as can be found: LICENSE-apache-2.0.txt.
|
||||||
|
|
||||||
|
Files licensed under MIT:
|
||||||
|
|
||||||
|
- FlashIAP.cpp
|
||||||
|
- FlashIAP.h
|
|
@ -147,7 +147,6 @@ ssize_t UARTSerial::write_unbuffered(const char *buf_ptr, size_t length)
|
||||||
|
|
||||||
for (size_t data_written = 0; data_written < length; data_written++) {
|
for (size_t data_written = 0; data_written < length; data_written++) {
|
||||||
SerialBase::_base_putc(*buf_ptr++);
|
SerialBase::_base_putc(*buf_ptr++);
|
||||||
data_written++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
|
|
|
@ -124,6 +124,13 @@ void GattClient<Impl>::terminateCharacteristicDescriptorDiscovery(
|
||||||
return impl()->terminateCharacteristicDescriptorDiscovery_(characteristic);
|
return impl()->terminateCharacteristicDescriptorDiscovery_(characteristic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Impl>
|
||||||
|
ble_error_t GattClient<Impl>::negotiateAttMtu(
|
||||||
|
ble::connection_handle_t connHandle
|
||||||
|
) {
|
||||||
|
return impl()->negotiateAttMtu_(connHandle);
|
||||||
|
}
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
ble_error_t GattClient<Impl>::reset(void)
|
ble_error_t GattClient<Impl>::reset(void)
|
||||||
{
|
{
|
||||||
|
@ -179,6 +186,13 @@ void GattClient<Impl>::terminateServiceDiscovery_(void)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class Impl>
|
||||||
|
ble_error_t GattClient<Impl>::negotiateAttMtu_(
|
||||||
|
ble::connection_handle_t connHandle
|
||||||
|
) {
|
||||||
|
return BLE_ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
ble_error_t GattClient<Impl>::read_(
|
ble_error_t GattClient<Impl>::read_(
|
||||||
ble::connection_handle_t connHandle,
|
ble::connection_handle_t connHandle,
|
||||||
|
|
|
@ -321,8 +321,10 @@ ble_error_t GattServer::insert_characteristic_value_attribute(
|
||||||
memset(attribute_it->pValue + *attribute_it->pLen, 0, attribute_it->maxLen - *attribute_it->pLen);
|
memset(attribute_it->pValue + *attribute_it->pLen, 0, attribute_it->maxLen - *attribute_it->pLen);
|
||||||
|
|
||||||
// Set value attribute settings
|
// Set value attribute settings
|
||||||
|
attribute_it->settings = 0;
|
||||||
|
|
||||||
if (properties & READ_PROPERTY) {
|
if (properties & READ_PROPERTY) {
|
||||||
attribute_it->settings = ATTS_SET_READ_CBACK;
|
attribute_it->settings |= ATTS_SET_READ_CBACK;
|
||||||
}
|
}
|
||||||
if (properties & WRITABLE_PROPERTIES) {
|
if (properties & WRITABLE_PROPERTIES) {
|
||||||
attribute_it->settings |= ATTS_SET_WRITE_CBACK;
|
attribute_it->settings |= ATTS_SET_WRITE_CBACK;
|
||||||
|
|
|
@ -121,7 +121,7 @@ void WsfTaskUnlock(void)
|
||||||
void WsfSetEvent(wsfHandlerId_t handlerId, wsfEventMask_t event)
|
void WsfSetEvent(wsfHandlerId_t handlerId, wsfEventMask_t event)
|
||||||
{
|
{
|
||||||
WSF_CS_INIT(cs);
|
WSF_CS_INIT(cs);
|
||||||
|
// coverity[CONSTANT_EXPRESSION_RESULT]
|
||||||
WSF_ASSERT(WSF_HANDLER_FROM_ID(handlerId) < WSF_MAX_HANDLERS);
|
WSF_ASSERT(WSF_HANDLER_FROM_ID(handlerId) < WSF_MAX_HANDLERS);
|
||||||
|
|
||||||
WSF_TRACE_INFO2("WsfSetEvent handlerId:%u event:%u", handlerId, event);
|
WSF_TRACE_INFO2("WsfSetEvent handlerId:%u event:%u", handlerId, event);
|
||||||
|
|
|
@ -1058,21 +1058,52 @@ bool ATHandler::consume_to_stop_tag()
|
||||||
|
|
||||||
void ATHandler::resp_stop()
|
void ATHandler::resp_stop()
|
||||||
{
|
{
|
||||||
// Do not return on error so that we can consume whatever there is in the buffer
|
if (_is_fh_usable) {
|
||||||
|
// Do not return on error so that we can consume whatever there is in the buffer
|
||||||
|
|
||||||
if (_current_scope == ElemType) {
|
if (_current_scope == ElemType) {
|
||||||
information_response_element_stop();
|
information_response_element_stop();
|
||||||
set_scope(InfoType);
|
set_scope(InfoType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_current_scope == InfoType) {
|
||||||
|
information_response_stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go for response stop_tag
|
||||||
|
if (_stop_tag && !_stop_tag->found && !_error_found) {
|
||||||
|
// Check for URC for every new line
|
||||||
|
while (!get_last_error()) {
|
||||||
|
|
||||||
|
if (match(_stop_tag->tag, _stop_tag->len)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match_urc()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no URC nor stop_tag found, look for CRLF and consume everything up to and including CRLF
|
||||||
|
if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) {
|
||||||
|
consume_to_tag(CRLF, true);
|
||||||
|
// If stop tag is CRLF we have to stop reading/consuming the buffer
|
||||||
|
if (!strncmp(CRLF, _stop_tag->tag, _stop_tag->len)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If no URC nor CRLF nor stop_tag -> fill buffer
|
||||||
|
} else {
|
||||||
|
if (!fill_buffer()) {
|
||||||
|
// if we don't get any match and no data within timeout, set an error to indicate need for recovery
|
||||||
|
set_error(NSAPI_ERROR_DEVICE_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_last_err = NSAPI_ERROR_BUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_current_scope == InfoType) {
|
set_scope(NotSet);
|
||||||
information_response_stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Go for response stop_tag
|
|
||||||
if (consume_to_stop_tag()) {
|
|
||||||
set_scope(NotSet);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restore stop tag to OK
|
// Restore stop tag to OK
|
||||||
set_tag(&_resp_stop, OK);
|
set_tag(&_resp_stop, OK);
|
||||||
|
@ -1289,7 +1320,7 @@ void ATHandler::debug_print(const char *p, int len, ATType type)
|
||||||
#if MBED_CONF_CELLULAR_DEBUG_AT
|
#if MBED_CONF_CELLULAR_DEBUG_AT
|
||||||
if (_debug_on) {
|
if (_debug_on) {
|
||||||
const int buf_size = len * 4 + 1; // x4 -> reserve space for extra characters, +1 -> terminating null
|
const int buf_size = len * 4 + 1; // x4 -> reserve space for extra characters, +1 -> terminating null
|
||||||
char *buffer = (char *)malloc(buf_size);
|
char *buffer = new char [buf_size];
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
memset(buffer, 0, buf_size);
|
memset(buffer, 0, buf_size);
|
||||||
|
|
||||||
|
@ -1319,7 +1350,7 @@ void ATHandler::debug_print(const char *p, int len, ATType type)
|
||||||
tr_info("AT ERR (%2d): %s", len, buffer);
|
tr_info("AT ERR (%2d): %s", len, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buffer);
|
delete [] buffer;
|
||||||
} else {
|
} else {
|
||||||
tr_error("AT trace unable to allocate buffer!");
|
tr_error("AT trace unable to allocate buffer!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -381,6 +381,10 @@ public:
|
||||||
/** Ends all scopes starting from current scope.
|
/** Ends all scopes starting from current scope.
|
||||||
* Consumes everything until the scope's stop tag is found, then
|
* Consumes everything until the scope's stop tag is found, then
|
||||||
* goes to next scope until response scope is ending.
|
* goes to next scope until response scope is ending.
|
||||||
|
* URC match is checked during response scope ending,
|
||||||
|
* for every new line / CRLF.
|
||||||
|
*
|
||||||
|
*
|
||||||
* Possible sequence:
|
* Possible sequence:
|
||||||
* element scope -> information response scope -> response scope
|
* element scope -> information response scope -> response scope
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -672,6 +672,10 @@ nsapi_error_t AT_CellularContext::disconnect()
|
||||||
{
|
{
|
||||||
tr_info("CellularContext disconnect()");
|
tr_info("CellularContext disconnect()");
|
||||||
if (!_nw || !_is_connected) {
|
if (!_nw || !_is_connected) {
|
||||||
|
if (_new_context_set) {
|
||||||
|
delete_current_context();
|
||||||
|
}
|
||||||
|
_cid = -1;
|
||||||
return NSAPI_ERROR_NO_CONNECTION;
|
return NSAPI_ERROR_NO_CONNECTION;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -701,6 +705,11 @@ nsapi_error_t AT_CellularContext::disconnect()
|
||||||
// call device's callback, it will broadcast this to here (cellular_callback)
|
// call device's callback, it will broadcast this to here (cellular_callback)
|
||||||
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this);
|
_device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this);
|
||||||
|
|
||||||
|
if (_new_context_set) {
|
||||||
|
delete_current_context();
|
||||||
|
}
|
||||||
|
_cid = -1;
|
||||||
|
|
||||||
return _at.unlock_return_error();
|
return _at.unlock_return_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,8 +47,6 @@ AT_CellularDevice::AT_CellularDevice(FileHandle *fh) : CellularDevice(fh), _netw
|
||||||
|
|
||||||
AT_CellularDevice::~AT_CellularDevice()
|
AT_CellularDevice::~AT_CellularDevice()
|
||||||
{
|
{
|
||||||
delete _state_machine;
|
|
||||||
|
|
||||||
// make sure that all is deleted even if somewhere close was not called and reference counting is messed up.
|
// make sure that all is deleted even if somewhere close was not called and reference counting is messed up.
|
||||||
_network_ref_count = 1;
|
_network_ref_count = 1;
|
||||||
_sms_ref_count = 1;
|
_sms_ref_count = 1;
|
||||||
|
|
|
@ -44,6 +44,7 @@ CellularDevice::CellularDevice(FileHandle *fh) : _network_ref_count(0), _sms_ref
|
||||||
CellularDevice::~CellularDevice()
|
CellularDevice::~CellularDevice()
|
||||||
{
|
{
|
||||||
tr_debug("CellularDevice destruct");
|
tr_debug("CellularDevice destruct");
|
||||||
|
delete _state_machine;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CellularDevice::stop()
|
void CellularDevice::stop()
|
||||||
|
@ -111,7 +112,10 @@ nsapi_error_t CellularDevice::create_state_machine()
|
||||||
{
|
{
|
||||||
nsapi_error_t err = NSAPI_ERROR_OK;
|
nsapi_error_t err = NSAPI_ERROR_OK;
|
||||||
if (!_state_machine) {
|
if (!_state_machine) {
|
||||||
_state_machine = new CellularStateMachine(*this, *get_queue());
|
_nw = open_network(_fh);
|
||||||
|
// Attach to network so we can get update status from the network
|
||||||
|
_nw->attach(callback(this, &CellularDevice::stm_callback));
|
||||||
|
_state_machine = new CellularStateMachine(*this, *get_queue(), *_nw);
|
||||||
_state_machine->set_cellular_callback(callback(this, &CellularDevice::stm_callback));
|
_state_machine->set_cellular_callback(callback(this, &CellularDevice::stm_callback));
|
||||||
err = _state_machine->start_dispatch();
|
err = _state_machine->start_dispatch();
|
||||||
if (err) {
|
if (err) {
|
||||||
|
@ -177,13 +181,6 @@ void CellularDevice::cellular_callback(nsapi_event_t ev, intptr_t ptr, CellularC
|
||||||
// broadcast only network registration changes to state machine
|
// broadcast only network registration changes to state machine
|
||||||
_state_machine->cellular_event_changed(ev, ptr);
|
_state_machine->cellular_event_changed(ev, ptr);
|
||||||
}
|
}
|
||||||
if (cell_ev == CellularDeviceReady && ptr_data->error == NSAPI_ERROR_OK) {
|
|
||||||
// Here we can create mux and give new filehandles as mux reserves the one what was in use.
|
|
||||||
// if mux we would need to set new filehandle:_state_machine->set_filehandle( get fh from mux);
|
|
||||||
_nw = open_network(_fh);
|
|
||||||
// Attach to network so we can get update status from the network
|
|
||||||
_nw->attach(callback(this, &CellularDevice::stm_callback));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tr_debug("callback: %d, ptr: %d", ev, ptr);
|
tr_debug("callback: %d, ptr: %d", ev, ptr);
|
||||||
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
|
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE && ptr == NSAPI_STATUS_DISCONNECTED) {
|
||||||
|
|
|
@ -43,9 +43,9 @@ const int DEVICE_READY = 0x04;
|
||||||
|
|
||||||
namespace mbed {
|
namespace mbed {
|
||||||
|
|
||||||
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue) :
|
CellularStateMachine::CellularStateMachine(CellularDevice &device, events::EventQueue &queue, CellularNetwork &nw) :
|
||||||
_cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state),
|
_cellularDevice(device), _state(STATE_INIT), _next_state(_state), _target_state(_state),
|
||||||
_event_status_cb(0), _network(0), _queue(queue), _queue_thread(0), _sim_pin(0),
|
_event_status_cb(0), _network(nw), _queue(queue), _queue_thread(0), _sim_pin(0),
|
||||||
_retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false),
|
_retry_count(0), _event_timeout(-1), _event_id(-1), _plmn(0), _command_success(false),
|
||||||
_is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE), _status(0)
|
_is_retry(false), _cb_data(), _current_event(NSAPI_EVENT_CONNECTION_STATUS_CHANGE), _status(0)
|
||||||
{
|
{
|
||||||
|
@ -99,11 +99,6 @@ void CellularStateMachine::stop()
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
_event_id = STM_STOPPED;
|
_event_id = STM_STOPPED;
|
||||||
|
|
||||||
if (_network) {
|
|
||||||
_cellularDevice.close_network();
|
|
||||||
_network = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CellularStateMachine::power_on()
|
bool CellularStateMachine::power_on()
|
||||||
|
@ -163,7 +158,7 @@ bool CellularStateMachine::open_sim()
|
||||||
if (sim_ready) {
|
if (sim_ready) {
|
||||||
// If plmn is set, we should it right after sim is opened so that registration is forced to correct network.
|
// If plmn is set, we should it right after sim is opened so that registration is forced to correct network.
|
||||||
if (_plmn && strlen(_plmn)) {
|
if (_plmn && strlen(_plmn)) {
|
||||||
_cb_data.error = _network->set_registration(_plmn);
|
_cb_data.error = _network.set_registration(_plmn);
|
||||||
tr_debug("STM: manual set_registration: %d, plmn: %s", _cb_data.error, _plmn);
|
tr_debug("STM: manual set_registration: %d, plmn: %s", _cb_data.error, _plmn);
|
||||||
if (_cb_data.error) {
|
if (_cb_data.error) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -204,7 +199,7 @@ bool CellularStateMachine::get_network_registration(CellularNetwork::Registratio
|
||||||
is_registered = false;
|
is_registered = false;
|
||||||
bool is_roaming = false;
|
bool is_roaming = false;
|
||||||
CellularNetwork::registration_params_t reg_params;
|
CellularNetwork::registration_params_t reg_params;
|
||||||
_cb_data.error = _network->get_registration_params(type, reg_params);
|
_cb_data.error = _network.get_registration_params(type, reg_params);
|
||||||
|
|
||||||
if (_cb_data.error != NSAPI_ERROR_OK) {
|
if (_cb_data.error != NSAPI_ERROR_OK) {
|
||||||
if (_cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
|
if (_cb_data.error != NSAPI_ERROR_UNSUPPORTED) {
|
||||||
|
@ -329,14 +324,10 @@ bool CellularStateMachine::device_ready()
|
||||||
{
|
{
|
||||||
tr_info("Modem ready");
|
tr_info("Modem ready");
|
||||||
|
|
||||||
if (!_network) {
|
|
||||||
_network = _cellularDevice.open_network();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY
|
#ifdef MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY
|
||||||
MBED_ASSERT(MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY >= CellularNetwork::RAT_GSM &&
|
MBED_ASSERT(MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY >= CellularNetwork::RAT_GSM &&
|
||||||
MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY < CellularNetwork::RAT_UNKNOWN);
|
MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY < CellularNetwork::RAT_UNKNOWN);
|
||||||
nsapi_error_t err = _network->set_access_technology((CellularNetwork::RadioAccessTechnology)MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY);
|
nsapi_error_t err = _network.set_access_technology((CellularNetwork::RadioAccessTechnology)MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY);
|
||||||
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
|
if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) {
|
||||||
tr_warning("Failed to set access technology to %d", MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY);
|
tr_warning("Failed to set access technology to %d", MBED_CONF_CELLULAR_RADIO_ACCESS_TECHNOLOGY);
|
||||||
return false;
|
return false;
|
||||||
|
@ -382,7 +373,7 @@ void CellularStateMachine::state_sim_pin()
|
||||||
if (open_sim()) {
|
if (open_sim()) {
|
||||||
bool success = false;
|
bool success = false;
|
||||||
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
|
for (int type = 0; type < CellularNetwork::C_MAX; type++) {
|
||||||
_cb_data.error = _network->set_registration_urc((CellularNetwork::RegistrationType)type, true);
|
_cb_data.error = _network.set_registration_urc((CellularNetwork::RegistrationType)type, true);
|
||||||
if (!_cb_data.error && (type == CellularNetwork::C_EREG || type == CellularNetwork::C_GREG)) {
|
if (!_cb_data.error && (type == CellularNetwork::C_EREG || type == CellularNetwork::C_GREG)) {
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
@ -393,19 +384,19 @@ void CellularStateMachine::state_sim_pin()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_network->is_active_context()) { // check if context was already activated
|
if (_network.is_active_context()) { // check if context was already activated
|
||||||
tr_debug("Active context found.");
|
tr_debug("Active context found.");
|
||||||
_status |= ACTIVE_PDP_CONTEXT;
|
_status |= ACTIVE_PDP_CONTEXT;
|
||||||
}
|
}
|
||||||
CellularNetwork::AttachStatus status = CellularNetwork::Detached; // check if modem is already attached to a network
|
CellularNetwork::AttachStatus status = CellularNetwork::Detached; // check if modem is already attached to a network
|
||||||
if (_network->get_attach(status) == NSAPI_ERROR_OK && status == CellularNetwork::Attached) {
|
if (_network.get_attach(status) == NSAPI_ERROR_OK && status == CellularNetwork::Attached) {
|
||||||
_status |= ATTACHED_TO_NETWORK;
|
_status |= ATTACHED_TO_NETWORK;
|
||||||
tr_debug("Cellular already attached.");
|
tr_debug("Cellular already attached.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// if packet domain event reporting is not set it's not a stopper. We might lack some events when we are
|
// if packet domain event reporting is not set it's not a stopper. We might lack some events when we are
|
||||||
// dropped from the network.
|
// dropped from the network.
|
||||||
_cb_data.error = _network->set_packet_domain_event_reporting(true);
|
_cb_data.error = _network.set_packet_domain_event_reporting(true);
|
||||||
if (_cb_data.error == NSAPI_STATUS_ERROR_UNSUPPORTED) {
|
if (_cb_data.error == NSAPI_STATUS_ERROR_UNSUPPORTED) {
|
||||||
tr_warning("Packet domain event reporting not supported!");
|
tr_warning("Packet domain event reporting not supported!");
|
||||||
} else if (_cb_data.error) {
|
} else if (_cb_data.error) {
|
||||||
|
@ -434,7 +425,7 @@ void CellularStateMachine::state_registering()
|
||||||
} else {
|
} else {
|
||||||
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
|
_cellularDevice.set_timeout(TIMEOUT_REGISTRATION);
|
||||||
if (!_command_success && !_plmn) { // don't call set_registration twice for manual registration
|
if (!_command_success && !_plmn) { // don't call set_registration twice for manual registration
|
||||||
_cb_data.error = _network->set_registration(_plmn);
|
_cb_data.error = _network.set_registration(_plmn);
|
||||||
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
|
_command_success = (_cb_data.error == NSAPI_ERROR_OK);
|
||||||
}
|
}
|
||||||
retry_state_or_fail();
|
retry_state_or_fail();
|
||||||
|
@ -446,7 +437,7 @@ void CellularStateMachine::state_attaching()
|
||||||
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
|
_cellularDevice.set_timeout(TIMEOUT_CONNECT);
|
||||||
tr_info("Attaching network (timeout %d s)", TIMEOUT_CONNECT / 1000);
|
tr_info("Attaching network (timeout %d s)", TIMEOUT_CONNECT / 1000);
|
||||||
if (_status != ATTACHED_TO_NETWORK) {
|
if (_status != ATTACHED_TO_NETWORK) {
|
||||||
_cb_data.error = _network->set_attach();
|
_cb_data.error = _network.set_attach();
|
||||||
}
|
}
|
||||||
if (_cb_data.error == NSAPI_ERROR_OK) {
|
if (_cb_data.error == NSAPI_ERROR_OK) {
|
||||||
if (_event_status_cb) {
|
if (_event_status_cb) {
|
||||||
|
@ -534,14 +525,12 @@ bool CellularStateMachine::get_current_status(CellularStateMachine::CellularStat
|
||||||
void CellularStateMachine::event()
|
void CellularStateMachine::event()
|
||||||
{
|
{
|
||||||
#if MBED_CONF_MBED_TRACE_ENABLE
|
#if MBED_CONF_MBED_TRACE_ENABLE
|
||||||
if (_network) {
|
int rssi;
|
||||||
int rssi;
|
if (_network.get_signal_quality(rssi) == NSAPI_ERROR_OK) {
|
||||||
if (_network->get_signal_quality(rssi) == NSAPI_ERROR_OK) {
|
if (rssi == CellularNetwork::SignalQualityUnknown) {
|
||||||
if (rssi == CellularNetwork::SignalQualityUnknown) {
|
tr_info("RSSI unknown");
|
||||||
tr_info("RSSI unknown");
|
} else {
|
||||||
} else {
|
tr_info("RSSI %d dBm", rssi);
|
||||||
tr_info("RSSI %d dBm", rssi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -643,7 +632,7 @@ void CellularStateMachine::cellular_event_changed(nsapi_event_t ev, intptr_t ptr
|
||||||
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) {
|
if ((cellular_connection_status_t)ev == CellularRegistrationStatusChanged && _state == STATE_REGISTERING_NETWORK) {
|
||||||
// expect packet data so only these states are valid
|
// expect packet data so only these states are valid
|
||||||
CellularNetwork::registration_params_t reg_params;
|
CellularNetwork::registration_params_t reg_params;
|
||||||
nsapi_error_t err = _network->get_registration_params(reg_params);
|
nsapi_error_t err = _network.get_registration_params(reg_params);
|
||||||
|
|
||||||
if (err == NSAPI_ERROR_OK && (reg_params._type == CellularNetwork::C_EREG || reg_params._type == CellularNetwork::C_GREG)) {
|
if (err == NSAPI_ERROR_OK && (reg_params._type == CellularNetwork::C_EREG || reg_params._type == CellularNetwork::C_GREG)) {
|
||||||
if ((data->status_data == CellularNetwork::RegisteredHomeNetwork ||
|
if ((data->status_data == CellularNetwork::RegisteredHomeNetwork ||
|
||||||
|
|
|
@ -46,8 +46,9 @@ private:
|
||||||
*
|
*
|
||||||
* @param device reference to CellularDevice
|
* @param device reference to CellularDevice
|
||||||
* @param queue reference to queue used in state transitions
|
* @param queue reference to queue used in state transitions
|
||||||
|
* @param nw reference to CellularNetwork
|
||||||
*/
|
*/
|
||||||
CellularStateMachine(CellularDevice &device, events::EventQueue &queue);
|
CellularStateMachine(CellularDevice &device, events::EventQueue &queue, CellularNetwork &nw);
|
||||||
~CellularStateMachine();
|
~CellularStateMachine();
|
||||||
|
|
||||||
/** Cellular connection states
|
/** Cellular connection states
|
||||||
|
@ -162,7 +163,7 @@ private:
|
||||||
|
|
||||||
Callback<void(nsapi_event_t, intptr_t)> _event_status_cb;
|
Callback<void(nsapi_event_t, intptr_t)> _event_status_cb;
|
||||||
|
|
||||||
CellularNetwork *_network;
|
CellularNetwork &_network;
|
||||||
events::EventQueue &_queue;
|
events::EventQueue &_queue;
|
||||||
rtos::Thread *_queue_thread;
|
rtos::Thread *_queue_thread;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,12 @@
|
||||||
|
|
||||||
using namespace mbed;
|
using namespace mbed;
|
||||||
|
|
||||||
|
const char *QIURC_RECV = "recv";
|
||||||
|
const uint8_t QIURC_RECV_LENGTH = 4;
|
||||||
|
const char *QIURC_CLOSED = "closed";
|
||||||
|
const uint8_t QIURC_CLOSED_LENGTH = 6;
|
||||||
|
const uint8_t MAX_QIURC_LENGTH = QIURC_CLOSED_LENGTH;
|
||||||
|
|
||||||
QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type)
|
QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type)
|
||||||
{
|
{
|
||||||
_at.set_urc_handler("+QIURC:", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc));
|
_at.set_urc_handler("+QIURC:", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc));
|
||||||
|
@ -110,20 +116,30 @@ nsapi_error_t QUECTEL_BG96_CellularStack::socket_connect(nsapi_socket_t handle,
|
||||||
|
|
||||||
void QUECTEL_BG96_CellularStack::urc_qiurc()
|
void QUECTEL_BG96_CellularStack::urc_qiurc()
|
||||||
{
|
{
|
||||||
int sock_id = 0;
|
char urc_string[MAX_QIURC_LENGTH + 1];
|
||||||
|
|
||||||
_at.lock();
|
_at.lock();
|
||||||
(void) _at.skip_param();
|
const int urc_string_length = _at.read_string(urc_string, sizeof(urc_string));
|
||||||
sock_id = _at.read_int();
|
const int sock_id = _at.read_int();
|
||||||
_at.unlock();
|
const nsapi_error_t err = _at.unlock_return_error();
|
||||||
|
|
||||||
for (int i = 0; i < get_max_socket_count(); i++) {
|
if (err != NSAPI_ERROR_OK) {
|
||||||
CellularSocket *sock = _socket[i];
|
return;
|
||||||
if (sock && sock->id == sock_id) {
|
}
|
||||||
|
|
||||||
|
bool recv = strcmp(urc_string, "recv") == 0;
|
||||||
|
bool closed = strcmp(urc_string, "closed") == 0;
|
||||||
|
|
||||||
|
CellularSocket *sock = find_socket(sock_id);
|
||||||
|
if (sock) {
|
||||||
|
if (closed) {
|
||||||
|
tr_error("Socket closed %d", sock_id);
|
||||||
|
sock->closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recv || closed) {
|
||||||
if (sock->_cb) {
|
if (sock->_cb) {
|
||||||
sock->_cb(sock->_data);
|
sock->_cb(sock->_data);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "QUECTEL_EC2X.h"
|
||||||
|
|
||||||
|
#include "PinNames.h"
|
||||||
|
#include "AT_CellularNetwork.h"
|
||||||
|
#include "rtos/ThisThread.h"
|
||||||
|
#include "UARTSerial.h"
|
||||||
|
|
||||||
|
using namespace mbed;
|
||||||
|
using namespace rtos;
|
||||||
|
using namespace events;
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_QUECTEL_EC2X_PWR)
|
||||||
|
#define MBED_CONF_QUECTEL_EC2X_PWR NC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_QUECTEL_EC2X_RST)
|
||||||
|
#define MBED_CONF_QUECTEL_EC2X_RST NC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_QUECTEL_EC2X_TX)
|
||||||
|
#define MBED_CONF_QUECTEL_EC2X_TX NC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_QUECTEL_EC2X_RX)
|
||||||
|
#define MBED_CONF_QUECTEL_EC2X_RX NC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_QUECTEL_EC2X_POLARITY)
|
||||||
|
#define MBED_CONF_QUECTEL_EC2X_POLARITY 1 // active high
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const intptr_t cellular_properties[AT_CellularBase::PROPERTY_MAX] = {
|
||||||
|
AT_CellularNetwork::RegistrationModeLAC, // C_EREG
|
||||||
|
AT_CellularNetwork::RegistrationModeLAC, // C_GREG
|
||||||
|
AT_CellularNetwork::RegistrationModeLAC, // C_REG
|
||||||
|
0, // AT_CGSN_WITH_TYPE
|
||||||
|
1, // AT_CGDATA
|
||||||
|
0, // AT_CGAUTH
|
||||||
|
1, // AT_CNMI
|
||||||
|
1, // AT_CSMP
|
||||||
|
1, // AT_CMGF
|
||||||
|
1, // AT_CSDH
|
||||||
|
1, // PROPERTY_IPV4_STACK
|
||||||
|
1, // PROPERTY_IPV6_STACK
|
||||||
|
1, // PROPERTY_IPV4V6_STACK
|
||||||
|
0, // PROPERTY_NON_IP_PDP_TYPE
|
||||||
|
1, // PROPERTY_AT_CGEREP
|
||||||
|
};
|
||||||
|
|
||||||
|
QUECTEL_EC2X::QUECTEL_EC2X(FileHandle *fh, PinName pwr, bool active_high, PinName rst)
|
||||||
|
: AT_CellularDevice(fh),
|
||||||
|
_active_high(active_high),
|
||||||
|
_pwr_key(pwr, !_active_high),
|
||||||
|
_rst(rst, !_active_high)
|
||||||
|
{
|
||||||
|
AT_CellularBase::set_cellular_properties(cellular_properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if MBED_CONF_QUECTEL_EC2X_PROVIDE_DEFAULT
|
||||||
|
CellularDevice *CellularDevice::get_default_instance()
|
||||||
|
{
|
||||||
|
static UARTSerial serial(MBED_CONF_QUECTEL_EC2X_TX,
|
||||||
|
MBED_CONF_QUECTEL_EC2X_RX,
|
||||||
|
MBED_CONF_QUECTEL_EC2X_BAUDRATE);
|
||||||
|
#if defined(MBED_CONF_QUECTEL_EC2X_RTS) && defined(MBED_CONF_QUECTEL_EC2X_CTS)
|
||||||
|
serial.set_flow_control(SerialBase::RTSCTS, MBED_CONF_QUECTEL_EC2X_RTS, MBED_CONF_QUECTEL_EC2X_CTS);
|
||||||
|
#endif
|
||||||
|
static QUECTEL_EC2X device(&serial,
|
||||||
|
MBED_CONF_QUECTEL_EC2X_PWR,
|
||||||
|
MBED_CONF_QUECTEL_EC2X_POLARITY,
|
||||||
|
MBED_CONF_QUECTEL_EC2X_RST);
|
||||||
|
return &device;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
nsapi_error_t QUECTEL_EC2X::press_power_button(uint32_t timeout)
|
||||||
|
{
|
||||||
|
_pwr_key = _active_high;
|
||||||
|
ThisThread::sleep_for(timeout);
|
||||||
|
_pwr_key = !_active_high;
|
||||||
|
ThisThread::sleep_for(100);
|
||||||
|
|
||||||
|
return NSAPI_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsapi_error_t QUECTEL_EC2X::hard_power_on()
|
||||||
|
{
|
||||||
|
return press_power_button(600);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsapi_error_t QUECTEL_EC2X::hard_power_off()
|
||||||
|
|
||||||
|
{
|
||||||
|
return press_power_button(750);
|
||||||
|
}
|
||||||
|
|
||||||
|
nsapi_error_t QUECTEL_EC2X::soft_power_on()
|
||||||
|
{
|
||||||
|
if (_rst.is_connected()) {
|
||||||
|
_rst = _active_high;
|
||||||
|
ThisThread::sleep_for(460);
|
||||||
|
_rst = !_active_high;
|
||||||
|
ThisThread::sleep_for(100);
|
||||||
|
|
||||||
|
_at->lock();
|
||||||
|
|
||||||
|
_at->set_at_timeout(5000);
|
||||||
|
_at->resp_start();
|
||||||
|
_at->set_stop_tag("RDY");
|
||||||
|
bool rdy = _at->consume_to_stop_tag();
|
||||||
|
_at->set_stop_tag(OK);
|
||||||
|
|
||||||
|
_at->unlock();
|
||||||
|
|
||||||
|
if (!rdy) {
|
||||||
|
return NSAPI_ERROR_DEVICE_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NSAPI_ERROR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsapi_error_t QUECTEL_EC2X::soft_power_off()
|
||||||
|
{
|
||||||
|
return hard_power_off();
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef QUECTEL_EC2X_H
|
||||||
|
#define QUECTEL_EC2X_H
|
||||||
|
|
||||||
|
#include "DigitalOut.h"
|
||||||
|
#include "AT_CellularDevice.h"
|
||||||
|
|
||||||
|
namespace mbed {
|
||||||
|
|
||||||
|
class QUECTEL_EC2X : public AT_CellularDevice {
|
||||||
|
public:
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs the Quectel EC2X series driver. It is mandatory to provide
|
||||||
|
* a FileHandle object, the power pin and the polarity of the pin.
|
||||||
|
* Providing reset pin is optional.
|
||||||
|
*/
|
||||||
|
QUECTEL_EC2X(FileHandle *fh, PinName pwr, bool active_high, PinName rst = NC);
|
||||||
|
|
||||||
|
virtual nsapi_error_t hard_power_on();
|
||||||
|
virtual nsapi_error_t hard_power_off();
|
||||||
|
virtual nsapi_error_t soft_power_on();
|
||||||
|
virtual nsapi_error_t soft_power_off();
|
||||||
|
|
||||||
|
private:
|
||||||
|
nsapi_error_t press_power_button(uint32_t timeout);
|
||||||
|
bool _active_high;
|
||||||
|
DigitalOut _pwr_key;
|
||||||
|
DigitalOut _rst;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace mbed
|
||||||
|
|
||||||
|
#endif // QUECTEL_EC2X_H
|
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"name": "QUECTEL_EC2X",
|
||||||
|
"config": {
|
||||||
|
"tx": {
|
||||||
|
"help": "TX pin for serial connection. D1 assumed if Arduino Form Factor, needs to be set/overwritten otherwise.",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"rx": {
|
||||||
|
"help": "RX pin for serial connection. D0 assumed if Arduino Form Factor, needs to be set/overwritten otherwise.",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"rts": {
|
||||||
|
"help": "RTS pin for serial connection",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"cts": {
|
||||||
|
"help": "CTS pin for serial connection",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"pwr": {
|
||||||
|
"help": "Power control pin",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"rst": {
|
||||||
|
"help": "Reset control pin",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"polarity": {
|
||||||
|
"help": "Pin polarity, 1 = Active high, 0 = Active low",
|
||||||
|
"value": null
|
||||||
|
},
|
||||||
|
"baudrate" : {
|
||||||
|
"help": "Serial connection baud rate",
|
||||||
|
"value": 115200
|
||||||
|
},
|
||||||
|
"provide-default": {
|
||||||
|
"help": "Provide as default CellularDevice [true/false]",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -467,7 +467,7 @@ nsapi_error_t LWIP::add_l3ip_interface(L3IP &l3ip, bool default_if, OnboardNetwo
|
||||||
#if LWIP_IPV4
|
#if LWIP_IPV4
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
#endif
|
#endif
|
||||||
interface, &LWIP::Interface::l3ip_if_init, ip_input)) {
|
interface, &LWIP::Interface::l3ip_if_init, tcpip_input)) {
|
||||||
return NSAPI_ERROR_DEVICE_ERROR;
|
return NSAPI_ERROR_DEVICE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -126,7 +126,7 @@ public:
|
||||||
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend LWIP;
|
friend class LWIP;
|
||||||
|
|
||||||
Interface();
|
Interface();
|
||||||
|
|
||||||
|
|
|
@ -403,6 +403,7 @@ bool test_socket_api_callbacks()
|
||||||
coap_conn_handler_t *handler = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, NULL, NULL);
|
coap_conn_handler_t *handler = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, NULL, NULL);
|
||||||
nsdynmemlib_stub.returnCounter = 2;
|
nsdynmemlib_stub.returnCounter = 2;
|
||||||
if (0 != coap_connection_handler_open_connection(handler, 22, false, false, true, false)) {
|
if (0 != coap_connection_handler_open_connection(handler, 22, false, false, true, false)) {
|
||||||
|
free(sckt_data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -483,6 +484,7 @@ bool test_security_callbacks()
|
||||||
coap_conn_handler_t *handler = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, NULL, NULL);
|
coap_conn_handler_t *handler = connection_handler_create(&receive_from_sock_cb, &send_to_sock_cb, NULL, NULL);
|
||||||
nsdynmemlib_stub.returnCounter = 2;
|
nsdynmemlib_stub.returnCounter = 2;
|
||||||
if (0 != coap_connection_handler_open_connection(handler, 22, false, true, true, false)) {
|
if (0 != coap_connection_handler_open_connection(handler, 22, false, true, true, false)) {
|
||||||
|
free(sckt_data);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
virtual nsapi_error_t bringdown();
|
virtual nsapi_error_t bringdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend Nanostack;
|
friend class Nanostack;
|
||||||
friend class NanostackEthernetInterface;
|
friend class NanostackEthernetInterface;
|
||||||
EthernetInterface(NanostackEthernetPhy &phy) : Interface(phy) {}
|
EthernetInterface(NanostackEthernetPhy &phy) : Interface(phy) {}
|
||||||
nsapi_error_t initialize();
|
nsapi_error_t initialize();
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
virtual nsapi_error_t bringdown();
|
virtual nsapi_error_t bringdown();
|
||||||
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
||||||
|
|
||||||
friend Nanostack;
|
friend class Nanostack;
|
||||||
friend class ::LoWPANNDInterface;
|
friend class ::LoWPANNDInterface;
|
||||||
private:
|
private:
|
||||||
LoWPANNDInterface(NanostackRfPhy &phy) : MeshInterface(phy) { }
|
LoWPANNDInterface(NanostackRfPhy &phy) : MeshInterface(phy) { }
|
||||||
|
|
|
@ -30,7 +30,7 @@ public:
|
||||||
nsapi_ip_stack_t stack = IPV6_STACK,
|
nsapi_ip_stack_t stack = IPV6_STACK,
|
||||||
bool blocking = true);
|
bool blocking = true);
|
||||||
virtual nsapi_error_t bringdown();
|
virtual nsapi_error_t bringdown();
|
||||||
friend Nanostack;
|
friend class Nanostack;
|
||||||
friend class ::ThreadInterface;
|
friend class ::ThreadInterface;
|
||||||
private:
|
private:
|
||||||
ThreadInterface(NanostackRfPhy &phy) : MeshInterface(phy), eui64_set(false) { }
|
ThreadInterface(NanostackRfPhy &phy) : MeshInterface(phy), eui64_set(false) { }
|
||||||
|
|
|
@ -33,7 +33,7 @@ public:
|
||||||
virtual nsapi_error_t bringdown();
|
virtual nsapi_error_t bringdown();
|
||||||
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
virtual char *get_gateway(char *buf, nsapi_size_t buflen);
|
||||||
|
|
||||||
friend Nanostack;
|
friend class Nanostack;
|
||||||
friend class ::WisunInterface;
|
friend class ::WisunInterface;
|
||||||
private:
|
private:
|
||||||
WisunInterface(NanostackRfPhy &phy) : MeshInterface(phy) { }
|
WisunInterface(NanostackRfPhy &phy) : MeshInterface(phy) { }
|
||||||
|
|
|
@ -103,9 +103,9 @@ static void initialize_channel_list(void)
|
||||||
|
|
||||||
arm_nwk_set_channel_list(tasklet_data_ptr->network_interface_id, &tasklet_data_ptr->channel_list);
|
arm_nwk_set_channel_list(tasklet_data_ptr->network_interface_id, &tasklet_data_ptr->channel_list);
|
||||||
|
|
||||||
tr_debug("Channel: %ld", channel);
|
tr_debug("Channel: %" PRIu32, channel);
|
||||||
tr_debug("Channel page: %d", tasklet_data_ptr->channel_list.channel_page);
|
tr_debug("Channel page: %d", tasklet_data_ptr->channel_list.channel_page);
|
||||||
tr_debug("Channel mask: 0x%.8lx", tasklet_data_ptr->channel_list.channel_mask[word_index]);
|
tr_debug("Channel mask: 0x%.8" PRIx32, tasklet_data_ptr->channel_list.channel_mask[word_index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -319,7 +319,7 @@ void thread_tasklet_configure_and_connect_to_network(void)
|
||||||
thread_tasklet_data_ptr->channel_list.channel_mask[0] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_MASK;
|
thread_tasklet_data_ptr->channel_list.channel_mask[0] = MBED_CONF_MBED_MESH_API_THREAD_CONFIG_CHANNEL_MASK;
|
||||||
|
|
||||||
TRACE_DETAIL("channel page: %d", thread_tasklet_data_ptr->channel_list.channel_page);
|
TRACE_DETAIL("channel page: %d", thread_tasklet_data_ptr->channel_list.channel_page);
|
||||||
TRACE_DETAIL("channel mask: 0x%.8lx", thread_tasklet_data_ptr->channel_list.channel_mask[0]);
|
TRACE_DETAIL("channel mask: 0x%.8" PRIx32, thread_tasklet_data_ptr->channel_list.channel_mask[0]);
|
||||||
|
|
||||||
// PSKd
|
// PSKd
|
||||||
const char PSKd[] = MBED_CONF_MBED_MESH_API_THREAD_PSKD;
|
const char PSKd[] = MBED_CONF_MBED_MESH_API_THREAD_PSKD;
|
||||||
|
|
|
@ -99,6 +99,9 @@ static void update_read_buffer(uint8_t *buf)
|
||||||
g_handle.rxBdCurrent[0]->buffer = buf;
|
g_handle.rxBdCurrent[0]->buffer = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensures buffer pointer is written before control. */
|
||||||
|
__DMB();
|
||||||
|
|
||||||
/* Clears status. */
|
/* Clears status. */
|
||||||
g_handle.rxBdCurrent[0]->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
|
g_handle.rxBdCurrent[0]->control &= ENET_BUFFDESCRIPTOR_RX_WRAP_MASK;
|
||||||
|
|
||||||
|
@ -112,6 +115,9 @@ static void update_read_buffer(uint8_t *buf)
|
||||||
g_handle.rxBdCurrent[0]++;
|
g_handle.rxBdCurrent[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensures descriptor is written before kicking hardware. */
|
||||||
|
__DSB();
|
||||||
|
|
||||||
/* Actives the receive buffer descriptor. */
|
/* Actives the receive buffer descriptor. */
|
||||||
ENET->RDAR = ENET_RDAR_RDAR_MASK;
|
ENET->RDAR = ENET_RDAR_RDAR_MASK;
|
||||||
}
|
}
|
||||||
|
@ -195,6 +201,7 @@ bool Kinetis_EMAC::low_level_init_successful()
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rx_ptr[i] = (uint32_t*)memory_manager->get_ptr(rx_buff[i]);
|
rx_ptr[i] = (uint32_t*)memory_manager->get_ptr(rx_buff[i]);
|
||||||
|
SCB_InvalidateDCache_by_Addr(rx_ptr[i], ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
tx_consume_index = tx_produce_index = 0;
|
tx_consume_index = tx_produce_index = 0;
|
||||||
|
@ -277,6 +284,7 @@ emac_mem_buf_t *Kinetis_EMAC::low_level_input(int idx)
|
||||||
|
|
||||||
/* Zero-copy */
|
/* Zero-copy */
|
||||||
p = rx_buff[idx];
|
p = rx_buff[idx];
|
||||||
|
SCB_InvalidateDCache_by_Addr(rx_ptr[idx], length);
|
||||||
memory_manager->set_len(p, length);
|
memory_manager->set_len(p, length);
|
||||||
|
|
||||||
/* Attempt to queue new buffer */
|
/* Attempt to queue new buffer */
|
||||||
|
@ -295,6 +303,7 @@ emac_mem_buf_t *Kinetis_EMAC::low_level_input(int idx)
|
||||||
|
|
||||||
rx_buff[idx] = temp_rxbuf;
|
rx_buff[idx] = temp_rxbuf;
|
||||||
rx_ptr[idx] = (uint32_t*)memory_manager->get_ptr(rx_buff[idx]);
|
rx_ptr[idx] = (uint32_t*)memory_manager->get_ptr(rx_buff[idx]);
|
||||||
|
SCB_InvalidateDCache_by_Addr(rx_ptr[idx], ENET_ALIGN(ENET_ETH_MAX_FLEN, ENET_BUFF_ALIGNMENT));
|
||||||
|
|
||||||
update_read_buffer((uint8_t*)rx_ptr[idx]);
|
update_read_buffer((uint8_t*)rx_ptr[idx]);
|
||||||
}
|
}
|
||||||
|
@ -399,6 +408,8 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
|
||||||
buf = copy_buf;
|
buf = copy_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SCB_CleanDCache_by_Addr(static_cast<uint32_t *>(memory_manager->get_ptr(buf)), memory_manager->get_len(buf));
|
||||||
|
|
||||||
/* Check if a descriptor is available for the transfer (wait 10ms before dropping the buffer) */
|
/* Check if a descriptor is available for the transfer (wait 10ms before dropping the buffer) */
|
||||||
if (xTXDCountSem.wait(10) == 0) {
|
if (xTXDCountSem.wait(10) == 0) {
|
||||||
memory_manager->free(buf);
|
memory_manager->free(buf);
|
||||||
|
@ -415,6 +426,8 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
|
||||||
/* Setup transfers */
|
/* Setup transfers */
|
||||||
g_handle.txBdCurrent[0]->buffer = static_cast<uint8_t *>(memory_manager->get_ptr(buf));
|
g_handle.txBdCurrent[0]->buffer = static_cast<uint8_t *>(memory_manager->get_ptr(buf));
|
||||||
g_handle.txBdCurrent[0]->length = memory_manager->get_len(buf);
|
g_handle.txBdCurrent[0]->length = memory_manager->get_len(buf);
|
||||||
|
/* Ensures buffer and length is written before control. */
|
||||||
|
__DMB();
|
||||||
g_handle.txBdCurrent[0]->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
|
g_handle.txBdCurrent[0]->control |= (ENET_BUFFDESCRIPTOR_TX_READY_MASK | ENET_BUFFDESCRIPTOR_TX_LAST_MASK);
|
||||||
|
|
||||||
/* Increase the buffer descriptor address. */
|
/* Increase the buffer descriptor address. */
|
||||||
|
@ -424,6 +437,9 @@ bool Kinetis_EMAC::link_out(emac_mem_buf_t *buf)
|
||||||
g_handle.txBdCurrent[0]++;
|
g_handle.txBdCurrent[0]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Ensures descriptor is written before kicking hardware. */
|
||||||
|
__DSB();
|
||||||
|
|
||||||
/* Active the transmit buffer descriptor. */
|
/* Active the transmit buffer descriptor. */
|
||||||
ENET->TDAR = ENET_TDAR_TDAR_MASK;
|
ENET->TDAR = ENET_TDAR_TDAR_MASK;
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
/* mbed Microcontroller Library
|
/*
|
||||||
* Copyright (c) 2017 ARM Limited
|
* Copyright (c) 2018-2019, Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* you may not use this file except in compliance with the License.
|
||||||
* in the Software without restriction, including without limitation the rights
|
* You may obtain a copy of the License at
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
|
||||||
* furnished to do so, subject to the following conditions:
|
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
* all copies or substantial portions of the Software.
|
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
* See the License for the specific language governing permissions and
|
||||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
* limitations under the License.
|
||||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
* SOFTWARE.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** \addtogroup storage */
|
/** \addtogroup storage */
|
||||||
|
|
|
@ -7,24 +7,24 @@ import os
|
||||||
import re
|
import re
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with open('blocks/config') as file:
|
with open('blocks/config', 'rb') as file:
|
||||||
s = struct.unpack('<LLLL', file.read())
|
s = struct.unpack('<LLLL', file.read())
|
||||||
print 'read_size: %d' % s[0]
|
print('read_size: %d' % s[0])
|
||||||
print 'prog_size: %d' % s[1]
|
print('prog_size: %d' % s[1])
|
||||||
print 'block_size: %d' % s[2]
|
print('block_size: %d' % s[2])
|
||||||
print 'block_size: %d' % s[3]
|
print('block_size: %d' % s[3])
|
||||||
|
|
||||||
print 'real_size: %d' % sum(
|
print('real_size: %d' % sum(
|
||||||
os.path.getsize(os.path.join('blocks', f))
|
os.path.getsize(os.path.join('blocks', f))
|
||||||
for f in os.listdir('blocks') if re.match('\d+', f))
|
for f in os.listdir('blocks') if re.match('\d+', f)))
|
||||||
|
|
||||||
with open('blocks/stats') as file:
|
with open('blocks/stats', 'rb') as file:
|
||||||
s = struct.unpack('<QQQ', file.read())
|
s = struct.unpack('<QQQ', file.read())
|
||||||
print 'read_count: %d' % s[0]
|
print('read_count: %d' % s[0])
|
||||||
print 'prog_count: %d' % s[1]
|
print('prog_count: %d' % s[1])
|
||||||
print 'erase_count: %d' % s[2]
|
print('erase_count: %d' % s[2])
|
||||||
|
|
||||||
print 'runtime: %.3f' % (time.time() - os.stat('blocks').st_ctime)
|
print('runtime: %.3f' % (time.time() - os.stat('blocks').st_ctime))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main(*sys.argv[1:])
|
main(*sys.argv[1:])
|
||||||
|
|
|
@ -14,6 +14,9 @@
|
||||||
"FUTURE_SEQUANA_M0_PSA": {
|
"FUTURE_SEQUANA_M0_PSA": {
|
||||||
"storage_type": "TDB_INTERNAL"
|
"storage_type": "TDB_INTERNAL"
|
||||||
},
|
},
|
||||||
|
"FUTURE_SEQUANA_PSA": {
|
||||||
|
"storage_type": "TDB_INTERNAL"
|
||||||
|
},
|
||||||
"CY8CKIT_062_WIFI_BT_M0_PSA": {
|
"CY8CKIT_062_WIFI_BT_M0_PSA": {
|
||||||
"storage_type": "TDB_INTERNAL"
|
"storage_type": "TDB_INTERNAL"
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,6 +15,10 @@
|
||||||
"internal_size": "0x8000",
|
"internal_size": "0x8000",
|
||||||
"internal_base_address": "0x10078000"
|
"internal_base_address": "0x10078000"
|
||||||
},
|
},
|
||||||
|
"FUTURE_SEQUANA_PSA": {
|
||||||
|
"internal_size": "0x8000",
|
||||||
|
"internal_base_address": "0x100F8000"
|
||||||
|
},
|
||||||
"CY8CKIT_062_WIFI_BT_M0_PSA": {
|
"CY8CKIT_062_WIFI_BT_M0_PSA": {
|
||||||
"internal_size": "0x8000",
|
"internal_size": "0x8000",
|
||||||
"internal_base_address": "0x10038000"
|
"internal_base_address": "0x10038000"
|
||||||
|
|
|
@ -23,7 +23,6 @@
|
||||||
|
|
||||||
MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line)
|
MBED_NORETURN void mbed_assert_internal(const char *expr, const char *file, int line)
|
||||||
{
|
{
|
||||||
core_util_critical_section_enter();
|
|
||||||
mbed_error(MBED_ERROR_ASSERTION_FAILED, expr, 0, file, line);
|
mbed_error(MBED_ERROR_ASSERTION_FAILED, expr, 0, file, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -74,6 +74,28 @@ void mbed_error_vprintf(const char *format, va_list arg)
|
||||||
|
|
||||||
void mbed_error_puts(const char *str)
|
void mbed_error_puts(const char *str)
|
||||||
{
|
{
|
||||||
|
// Writing the string to the console in a critical section is
|
||||||
|
// potentially beneficial - for example in UARTSerial it
|
||||||
|
// forces the "unbuffered" mode that makes sure all characters
|
||||||
|
// go out now. If we made the call not in a critical section,
|
||||||
|
// it would go to the software buffer and we would be reliant
|
||||||
|
// on platform.stdio-flush-at-exit forcing a fsync before
|
||||||
|
// entering mbed_die().
|
||||||
|
//
|
||||||
|
// But this may be the very first write to the console, and hence
|
||||||
|
// require it to be initialized - doing this in a critical
|
||||||
|
// section could be problematic. So we prime it outside the
|
||||||
|
// critical section with a zero-length write - this forces
|
||||||
|
// the initialization.
|
||||||
|
//
|
||||||
|
// It's still possible that we were in a critical section
|
||||||
|
// or interrupt on entry anyway (eg if this is an error coming
|
||||||
|
// from inside RTX), so in other areas of the system we suppress
|
||||||
|
// things like mutex creation asserts and RTX traps while
|
||||||
|
// an error is in progress, so that console initialization
|
||||||
|
// may work.
|
||||||
|
write(STDERR_FILENO, str, 0);
|
||||||
|
|
||||||
core_util_critical_section_enter();
|
core_util_critical_section_enter();
|
||||||
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES || MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES
|
#if MBED_CONF_PLATFORM_STDIO_CONVERT_NEWLINES || MBED_CONF_PLATFORM_STDIO_CONVERT_TTY_NEWLINES
|
||||||
char stdio_out_prev = '\0';
|
char stdio_out_prev = '\0';
|
||||||
|
|
|
@ -28,15 +28,12 @@ extern "C" {
|
||||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Base[];
|
extern uint32_t Image$$RW_m_crash_data$$ZI$$Base[];
|
||||||
extern uint32_t Image$$RW_m_crash_data$$ZI$$Size;
|
extern uint32_t Image$$RW_m_crash_data$$ZI$$Size;
|
||||||
#define __CRASH_DATA_RAM_START__ Image$$RW_m_crash_data$$ZI$$Base
|
#define __CRASH_DATA_RAM_START__ Image$$RW_m_crash_data$$ZI$$Base
|
||||||
#define __CRASH_DATA_RAM_SIZE__ Image$$RW_m_crash_data$$ZI$$Size
|
|
||||||
#elif defined(__ICCARM__)
|
#elif defined(__ICCARM__)
|
||||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
extern uint32_t __CRASH_DATA_RAM_START__[];
|
||||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
extern uint32_t __CRASH_DATA_RAM_END__[];
|
||||||
#define __CRASH_DATA_RAM_SIZE__ (__CRASH_DATA_RAM_END__ - __CRASH_DATA_RAM_START__)
|
|
||||||
#elif defined(__GNUC__)
|
#elif defined(__GNUC__)
|
||||||
extern uint32_t __CRASH_DATA_RAM_START__[];
|
extern uint32_t __CRASH_DATA_RAM_START__[];
|
||||||
extern uint32_t __CRASH_DATA_RAM_END__[];
|
extern uint32_t __CRASH_DATA_RAM_END__[];
|
||||||
#define __CRASH_DATA_RAM_SIZE__ (__CRASH_DATA_RAM_END__ - __CRASH_DATA_RAM_START__)
|
|
||||||
#endif /* defined(__CC_ARM) */
|
#endif /* defined(__CC_ARM) */
|
||||||
|
|
||||||
/* Offset definitions for context capture */
|
/* Offset definitions for context capture */
|
||||||
|
|
|
@ -45,7 +45,7 @@ static void print_error_report(const mbed_error_ctx *ctx, const char *, const ch
|
||||||
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
|
#define ERROR_REPORT(ctx, error_msg, error_filename, error_line) ((void) 0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static core_util_atomic_flag error_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
static bool error_in_progress;
|
||||||
static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
static core_util_atomic_flag halt_in_progress = CORE_UTIL_ATOMIC_FLAG_INIT;
|
||||||
static int error_count = 0;
|
static int error_count = 0;
|
||||||
static mbed_error_ctx first_error_ctx = {0};
|
static mbed_error_ctx first_error_ctx = {0};
|
||||||
|
@ -115,7 +115,7 @@ static MBED_NORETURN void mbed_halt_system(void)
|
||||||
WEAK MBED_NORETURN void error(const char *format, ...)
|
WEAK MBED_NORETURN void error(const char *format, ...)
|
||||||
{
|
{
|
||||||
// Prevent recursion if error is called again during store+print attempt
|
// Prevent recursion if error is called again during store+print attempt
|
||||||
if (!core_util_atomic_flag_test_and_set(&error_in_progress)) {
|
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
|
||||||
handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
|
handle_error(MBED_ERROR_UNKNOWN, 0, NULL, 0, MBED_CALLER_ADDR());
|
||||||
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);
|
ERROR_REPORT(&last_error_ctx, "Fatal Run-time error", NULL, 0);
|
||||||
|
|
||||||
|
@ -256,6 +256,12 @@ int mbed_get_error_count(void)
|
||||||
return error_count;
|
return error_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Reads the fatal error occurred" flag
|
||||||
|
bool mbed_get_error_in_progress(void)
|
||||||
|
{
|
||||||
|
return core_util_atomic_load_bool(&error_in_progress);
|
||||||
|
}
|
||||||
|
|
||||||
//Sets a non-fatal error
|
//Sets a non-fatal error
|
||||||
mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
|
mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
|
||||||
{
|
{
|
||||||
|
@ -266,7 +272,7 @@ mbed_error_status_t mbed_warning(mbed_error_status_t error_status, const char *e
|
||||||
WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
|
WEAK MBED_NORETURN mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number)
|
||||||
{
|
{
|
||||||
// Prevent recursion if error is called again during store+print attempt
|
// Prevent recursion if error is called again during store+print attempt
|
||||||
if (!core_util_atomic_flag_test_and_set(&error_in_progress)) {
|
if (!core_util_atomic_exchange_bool(&error_in_progress, true)) {
|
||||||
//set the error reported
|
//set the error reported
|
||||||
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
|
(void) handle_error(error_status, error_value, filename, line_number, MBED_CALLER_ADDR());
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#ifndef MBED_ERROR_H
|
#ifndef MBED_ERROR_H
|
||||||
#define MBED_ERROR_H
|
#define MBED_ERROR_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include "platform/mbed_retarget.h"
|
#include "platform/mbed_retarget.h"
|
||||||
#include "platform/mbed_toolchain.h"
|
#include "platform/mbed_toolchain.h"
|
||||||
|
|
||||||
|
@ -50,14 +51,17 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MBED_ERROR_STATUS_CODE_MASK (0x0000FFFF)
|
#define MBED_ERROR_STATUS_CODE_MASK (0x0000FFFF)
|
||||||
|
#define MBED_ERROR_STATUS_CODE_UNSHIFTED_MASK (0x0000FFFF)
|
||||||
#define MBED_ERROR_STATUS_CODE_POS (0)
|
#define MBED_ERROR_STATUS_CODE_POS (0)
|
||||||
#define MBED_ERROR_STATUS_CODE_FIELD_SIZE (16)
|
#define MBED_ERROR_STATUS_CODE_FIELD_SIZE (16)
|
||||||
|
|
||||||
#define MBED_ERROR_STATUS_MODULE_MASK (0x00FF0000)
|
#define MBED_ERROR_STATUS_MODULE_MASK (0x00FF0000)
|
||||||
|
#define MBED_ERROR_STATUS_MODULE_UNSHIFTED_MASK (0x000000FF)
|
||||||
#define MBED_ERROR_STATUS_MODULE_POS (16)
|
#define MBED_ERROR_STATUS_MODULE_POS (16)
|
||||||
#define MBED_ERROR_STATUS_MODULE_FIELD_SIZE (8)
|
#define MBED_ERROR_STATUS_MODULE_FIELD_SIZE (8)
|
||||||
|
|
||||||
#define MBED_ERROR_STATUS_TYPE_MASK (0x60000000)
|
#define MBED_ERROR_STATUS_TYPE_MASK (0x60000000)
|
||||||
|
#define MBED_ERROR_STATUS_TYPE_UNSHIFTED_MASK (0x00000003)
|
||||||
#define MBED_ERROR_STATUS_TYPE_POS (29)
|
#define MBED_ERROR_STATUS_TYPE_POS (29)
|
||||||
#define MBED_ERROR_STATUS_TYPE_FIELD_SIZE (2)
|
#define MBED_ERROR_STATUS_TYPE_FIELD_SIZE (2)
|
||||||
|
|
||||||
|
@ -65,11 +69,11 @@ extern "C" {
|
||||||
//|31(1 bit) Always Negative|30-29(2 bits) |28-24 | 23-16(8 bits) | 15-0(16 bits) |
|
//|31(1 bit) Always Negative|30-29(2 bits) |28-24 | 23-16(8 bits) | 15-0(16 bits) |
|
||||||
//|-1 |TYPE |(unused/reserved) | MODULE TYPE | ERROR CODE |
|
//|-1 |TYPE |(unused/reserved) | MODULE TYPE | ERROR CODE |
|
||||||
|
|
||||||
#define MAKE_MBED_ERROR(type, module, error_code) (mbed_error_status_t) \
|
#define MAKE_MBED_ERROR(type, module, error_code) (mbed_error_status_t) \
|
||||||
((0x80000000) | \
|
((0x80000000) | \
|
||||||
(MBED_ERROR_STATUS_CODE_MASK & (error_code << MBED_ERROR_STATUS_CODE_POS)) | \
|
((mbed_error_status_t) (error_code & MBED_ERROR_STATUS_CODE_UNSHIFTED_MASK) << MBED_ERROR_STATUS_CODE_POS) | \
|
||||||
(MBED_ERROR_STATUS_MODULE_MASK & (module << MBED_ERROR_STATUS_MODULE_POS)) | \
|
((mbed_error_status_t) (module & MBED_ERROR_STATUS_MODULE_UNSHIFTED_MASK) << MBED_ERROR_STATUS_MODULE_POS) | \
|
||||||
(MBED_ERROR_STATUS_TYPE_MASK & (type << MBED_ERROR_STATUS_TYPE_POS)))
|
((mbed_error_status_t) (type & MBED_ERROR_STATUS_TYPE_UNSHIFTED_MASK) << MBED_ERROR_STATUS_TYPE_POS))
|
||||||
|
|
||||||
#define MBED_GET_ERROR_TYPE( error_status ) ((error_status & MBED_ERROR_STATUS_TYPE_MASK) >> MBED_ERROR_STATUS_TYPE_POS)
|
#define MBED_GET_ERROR_TYPE( error_status ) ((error_status & MBED_ERROR_STATUS_TYPE_MASK) >> MBED_ERROR_STATUS_TYPE_POS)
|
||||||
#define MBED_GET_ERROR_MODULE( error_status ) ((error_status & MBED_ERROR_STATUS_MODULE_MASK) >> MBED_ERROR_STATUS_MODULE_POS)
|
#define MBED_GET_ERROR_MODULE( error_status ) ((error_status & MBED_ERROR_STATUS_MODULE_MASK) >> MBED_ERROR_STATUS_MODULE_POS)
|
||||||
|
@ -83,7 +87,7 @@ extern "C" {
|
||||||
*
|
*
|
||||||
\verbatim
|
\verbatim
|
||||||
| 31 Always Negative | 30-29(2 bits) | 28-24 | 23-16(8 bits) | 15-0(16 bits) |
|
| 31 Always Negative | 30-29(2 bits) | 28-24 | 23-16(8 bits) | 15-0(16 bits) |
|
||||||
| -1 | TYPE | (unused/reserved) | MODULE TYPE | ERROR CODE |
|
| -1 | TYPE | (unused/reserved) | MODULE TYPE | ERROR CODE |
|
||||||
\endverbatim
|
\endverbatim
|
||||||
*
|
*
|
||||||
* The error status value range for each error type is as follows:\n
|
* The error status value range for each error type is as follows:\n
|
||||||
|
@ -1036,6 +1040,13 @@ mbed_error_status_t mbed_get_last_error(void);
|
||||||
*/
|
*/
|
||||||
int mbed_get_error_count(void);
|
int mbed_get_error_count(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether we are processing a fatal mbed error.
|
||||||
|
* @return bool Whether a fatal error has occurred.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
bool mbed_get_error_in_progress(void);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report and halts the system.
|
* Call this function to set a fatal system error and halt the system. This function will log the fatal error with the context info and prints the error report and halts the system.
|
||||||
*
|
*
|
||||||
|
|
|
@ -127,7 +127,9 @@ MBED_NORETURN void mbed_die(void);
|
||||||
/** Print out an error message. This is typically called when
|
/** Print out an error message. This is typically called when
|
||||||
* handling a crash.
|
* handling a crash.
|
||||||
*
|
*
|
||||||
* @note Synchronization level: Interrupt safe
|
* @note Synchronization level: Interrupt safe, as long as the
|
||||||
|
* FileHandle::write of the stderr device is. See mbed_error_puts
|
||||||
|
* for more information.
|
||||||
* @note This uses an internal 128-byte buffer to format the string,
|
* @note This uses an internal 128-byte buffer to format the string,
|
||||||
* so the output may be truncated. If you need to write a potentially
|
* so the output may be truncated. If you need to write a potentially
|
||||||
* long string, use mbed_error_puts.
|
* long string, use mbed_error_puts.
|
||||||
|
@ -145,7 +147,9 @@ void mbed_error_printf(const char *format, ...) MBED_PRINTF(1, 2);
|
||||||
/** Print out an error message. Similar to mbed_error_printf
|
/** Print out an error message. Similar to mbed_error_printf
|
||||||
* but uses a va_list.
|
* but uses a va_list.
|
||||||
*
|
*
|
||||||
* @note Synchronization level: Interrupt safe
|
* @note Synchronization level: Interrupt safe, as long as the
|
||||||
|
* FileHandle::write of the stderr device is. See mbed_error_puts
|
||||||
|
* for more information.
|
||||||
*
|
*
|
||||||
* @param format C string that contains data stream to be printed.
|
* @param format C string that contains data stream to be printed.
|
||||||
* @param arg Variable arguments list
|
* @param arg Variable arguments list
|
||||||
|
@ -160,7 +164,13 @@ void mbed_error_vprintf(const char *format, va_list arg) MBED_PRINTF(1, 0);
|
||||||
* length. Unlike standard puts, but like standard fputs, this does not
|
* length. Unlike standard puts, but like standard fputs, this does not
|
||||||
* append a '\n' character.
|
* append a '\n' character.
|
||||||
*
|
*
|
||||||
* @note Synchronization level: Interrupt safe
|
* @note Synchronization level: Interrupt safe, as long as the
|
||||||
|
* FileHandle::write of the stderr device is. The default
|
||||||
|
* serial console is safe, either buffered or not. If the
|
||||||
|
* console has not previously been initialized, an attempt
|
||||||
|
* to use this from interrupt may during console initialization.
|
||||||
|
* Special handling of `mbed_error` relaxes various system traps
|
||||||
|
* to increase the chance of initialization working.
|
||||||
*
|
*
|
||||||
* @param str C string that contains data stream to be printed.
|
* @param str C string that contains data stream to be printed.
|
||||||
*
|
*
|
||||||
|
|
|
@ -183,6 +183,10 @@
|
||||||
"crash-capture-enabled": true,
|
"crash-capture-enabled": true,
|
||||||
"fatal-error-auto-reboot-enabled": true
|
"fatal-error-auto-reboot-enabled": true
|
||||||
},
|
},
|
||||||
|
"NUMAKER_PFM_NUC472": {
|
||||||
|
"crash-capture-enabled": true,
|
||||||
|
"fatal-error-auto-reboot-enabled": true
|
||||||
|
},
|
||||||
"NRF52840_DK": {
|
"NRF52840_DK": {
|
||||||
"crash-capture-enabled": true,
|
"crash-capture-enabled": true,
|
||||||
"fatal-error-auto-reboot-enabled": true
|
"fatal-error-auto-reboot-enabled": true
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue